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
|
#ifndef PHASEFIX_H
#define PHASEFIX_H
/*
* 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
*
*
* phasefix.h
*
* Functions for correcting Breakpoint phases and frequencies so that
* stored phases match the phases that would be synthesized using the
* Loris Synthesizer.
*
* Kelly Fitz, 23 Sept 04
* loris@cerlsoundgroup.org
*
* http://www.cerlsoundgroup.org/Loris/
*
*/
#include "Partial.h"
// begin namespace
namespace Loris {
// FUNCTION PROTOYPES
// fixPhaseBackward
//
//! Recompute phases of all Breakpoints on the half-open range [stopHere, pos)
//! so that the synthesized phases of those Breakpoints matches
//! the stored phase, as long as the synthesized phase at stopHere
//! matches the stored (not recomputed) phase.
//!
//! The phase is corrected beginning at the end of the range, maintaining
//! the stored phase in the Breakpoint at pos.
//!
//! Backward phase-fixing stops if a null (zero-amplitude) Breakpoint
//! is encountered, because nulls are interpreted as phase reset points
//! in Loris. If a null is encountered, the remainder of the range
//! (the front part) is fixed in the forward direction, beginning at
//! the start of the stopHere.
//!
//! \pre pos and stopHere are iterators on the same Partial, and
//! pos must be not later than stopHere.
//! \pre pos cannot be end of the Partial, it must be the postion
//! of a valid Breakpoint.
//! \param stopHere the position of the earliest Breakpoint whose phase might be
//! recomputed.
//! \param pos the position of a (later) Breakpoint whose phase is to be matched.
//! The phase at pos is not modified.
//
void fixPhaseBackward( Partial::iterator stopHere, Partial::iterator pos );
// fixPhaseForward
//
//! Recompute phases of all Breakpoints on the closed range [pos, stopHere]
//! so that the synthesized phases of those Breakpoints matches
//! the stored phase, as long as the synthesized phase at pos
//! matches the stored (not recomputed) phase. The phase at pos
//! is modified only if pos is the position of a null Breakpoint
//! and the Breakpoint that follows is non-null.
//!
//! Phase fixing is only applied to non-null (nonzero-amplitude) Breakpoints,
//! because null Breakpoints are interpreted as phase reset points in
//! Loris. If a null is encountered, its phase is corrected from its non-Null
//! successor, if it has one, otherwise it is unmodified.
//!
//! \pre pos and stopHere are iterators on the same Partial, and
//! pos must be not later than stopHere.
//! \pre stopHere cannot be end of the Partial, it must be the postion
//! of a valid Breakpoint.
//! \param pos the position of the first Breakpoint whose phase might be
//! recomputed.
//! \param stopHere the position of the last Breakpoint whose phase might
//! be modified.
//
void fixPhaseForward( Partial::iterator pos, Partial::iterator stopHere );
// ---------------------------------------------------------------------------
// fixPhaseBetween
//
//! Fix the phase travel between two Breakpoints by adjusting the
//! frequency and phase of Breakpoints between those two.
//!
//! This algorithm assumes that there is nothing interesting about the
//! phases of the intervening Breakpoints, and modifies their frequencies
//! as little as possible to achieve the correct amount of phase travel
//! such that the frequencies and phases at the specified times
//! match the stored values. The phases of all the Breakpoints between
//! the specified times are recomputed.
//!
//! Null Breakpoints are treated the same as non-null Breakpoints.
//!
//! \pre b and e are iterators on the same Partials, and
//! e must not preceed b in that Partial.
//! \pre There must be at least one Breakpoint in the
//! Partial between b and e.
//! \post The phases and frequencies of the Breakpoints in the
//! range have been recomputed such that an oscillator
//! initialized to the parameters of the first Breakpoint
//! will arrive at the parameters of the last Breakpoint,
//! and all the intervening Breakpoints will be matched.
//! \param b The phases and frequencies of Breakpoints later than
//! this one may be modified.
//! \param e The phases and frequencies of Breakpoints earlier than
//! this one may be modified.
//
void fixPhaseBetween( Partial::iterator b, Partial::iterator e );
// fixFrequency
//
//! Adjust frequencies of the Breakpoints in the
//! specified Partial such that the rendered Partial
//! achieves (or matches as nearly as possible, within
//! the constraint of the maximum allowable frequency
//! alteration) the analyzed phases.
//!
//! \param partial The Partial whose frequencies,
//! and possibly phases (if the frequencies
//! cannot be sufficiently altered to match
//! the phases), will be recomputed.
//! \param maxFixPct The maximum allowable frequency
//! alteration, default is 0.2%.
//
void fixFrequency( Partial & partial, double maxFixPct = 0.2 );
// fixFrequency
//
//! Adjust frequencies of the Breakpoints in the
//! specified Partials such that the rendered Partial
//! achieves (or matches as nearly as possible, within
//! the constraint of the maximum allowable frequency
//! alteration) the analyzed phases.
//!
//! \param b The beginning of a range of Partials whose
//! frequencies should be fixed.
//! \param e The end of a range of Partials whose frequencies
//! should be fixed.
//! \param maxFixPct The maximum allowable frequency
//! alteration, default is 0.2%.
//
template < class Iter >
void fixFrequency( Iter b, Iter e, double maxFixPct = 0.2 )
{
while ( b != e )
{
fixFrequency( *b, maxFixPct );
++b;
}
}
// --------------------- useful phase maintenance utilities ---------------------
// matchPhaseFwd
//
//! Compute the target frequency that will affect the
//! predicted (by the Breakpoint phases) amount of
//! sinusoidal phase travel between two breakpoints,
//! and assign that frequency to the target Breakpoint.
//! After computing the new frequency, update the phase of
//! the later Breakpoint.
//!
//! The most common kinds of errors are local (or burst) errors in
//! frequency and phase. These errors are best corrected by correcting
//! less than half the detected error at any time. Correcting more
//! than that will produce frequency oscillations for the remainder of
//! the Partial, in the case of a single bad frequency (as is common
//! at the onset of a tone). Any damping factor less then one will
//! converge eventually, .5 or less will converge without oscillating.
//! Use the damping argument to control the damping of the correction.
//! Specify 1 for no damping.
//!
//!
//! \pre The two Breakpoints are assumed to be consecutive in
//! a Partial.
//! \param bp0 The earlier Breakpoint.
//! \param bp1 The later Breakpoint.
//! \param dt The time (in seconds) between bp0 and bp1.
//! \param damping The fraction of the amount of phase error that will
//! be corrected (.5 or less will prevent frequency oscilation
//! due to burst errors in phase).
//! \param maxFixPct The maximum amount of frequency adjustment
//! that can be made to the frequency of bp1, expressed
//! as a precentage of the unmodified frequency of bp1.
//! If the necessary amount of frequency adjustment exceeds
//! this amount, then the phase will not be matched,
//! but will be updated as well to be consistent with
//! the frequencies. (default is 0.2%)
//
void matchPhaseFwd( Breakpoint & bp0, Breakpoint & bp1,
double dt, double damping, double maxFixPct = 0.2 );
// phaseTravel
//
//! Compute the sinusoidal phase travel between two Breakpoints.
//! Return the total unwrapped phase travel.
//!
//! \pre The two Breakpoints are assumed to be consecutive in
//! a Partial.
//! \param bp0 The earlier Breakpoint.
//! \param bp1 The later Breakpoint.
//! \param dt The time (in seconds) between bp0 and bp1.
//! \return The total unwrapped phase travel in radians.
//
double phaseTravel( const Breakpoint & bp0, const Breakpoint & bp1, double dt );
// wrapPi
//
//! Wrap an unwrapped phase value to the range (-pi,pi].
//!
//! \param x The unwrapped phase in radians.
//! \return The phase (in radians) wrapped to the range (-Pi,Pi].
//
double wrapPi( double x );
} // end of namespace Loris
#endif // ndef PHASEFIX_H
|