1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
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
|