Jamoma API  0.6.0.a19
CrossFadeQueue.cpp
1 // CrossFadeQueue.cpp
2 /***************************************************/
3 /*! \class CrossFadeQueue
4  \brief CrossFadeQueue class
5 
6  This class implements a sound source, which consists
7  of variables that are common to all crossfades, as well as the
8  queue of crossfade events.
9 
10  by Tristan Matthews and Nils Peters, 2007-2008.
11  */
12 /***************************************************/
13 
14 #include "CrossFade.h"
15 #include "CrossFadeQueue.h"
16 #include "Properties.h"
17 #if defined(TT_PLATFORM_MAC)
18 //#include <Multiprocessing.h>
19 #include <CoreServices/CoreServices.h>
20 #endif
21 #include "ext_critical.h" //FIXME: this amy be added globally ?
22 #include "TTBase.h"
23 
24 #include <cassert>
25 #include <deque>
26 #include <vector>
27 
28 extern bool globReportFlag;
29 extern bool globWarningFlag;
30 
31 CrossFadeQueue::CrossFadeQueue(long newFadeThreshold, long newFadeLength, Properties::fadeMode fadeType, double sampleRate) :
32  changed_(true),
33  fadeThreshold_(newFadeThreshold),
34  fadeLength_(newFadeLength),
35  fadeTbl_(),
36  sampleRate_(sampleRate),
37  fadeType_(fadeType),
38  fadeQueue_()
39 {
40  if (fadeLength_ <= 0)
41  {
42  fadeLength_ = 64;
43  if (globWarningFlag)
44  post ("Invalid fadelength, set to default of %d samps", fadeLength_);
45  }
46 
47  notifyCrossFades();
48  computeFadeTbl();
49 }
50 
52 {
53  // delete any Crossfades still in queue.
54  while (!fadeQueue_.empty())
55  {
56  delete fadeQueue_.front();
57  fadeQueue_.pop_front();
58  }
59 }
60 
61 double CrossFadeQueue::getTblValAt(int index) const
62 {
63  return fadeTbl_[index];
64 }
65 
67 {
68  return fadeLength_;
69 }
70 
71 void CrossFadeQueue::fadeLength(long newFadeLength)
72 {
73  if (newFadeLength > 0)
74  {
75  fadeLength_ = newFadeLength;
76 
77  changed_ = true;
78  notifyCrossFades();
79 
80  computeFadeTbl();
81  }
82  else if (globWarningFlag)
83  error("Invalid fadelength %d, no action taken", newFadeLength);
84 
85  if (globReportFlag)
86  post("FadeLength: %d", fadeLength_);
87 }
88 
89 void CrossFadeQueue::fadeFunction(Properties::fadeMode fadeType)
90 {
91  fadeType_ = fadeType;
92  computeFadeTbl();
93  if (globReportFlag)
94  {
95  switch (fadeType_)
96  {
97  case Properties::COS_SQUARED:
98  post("x-fade fade-function: cosine squared");
99  break;
100 
101  case Properties::COS:
102  post("x-fade fade-function: cosine");
103  break;
104 
105  case Properties::LINEAR:
106  post("x-fade fade-function: linear");
107  break;
108 
109  case Properties::TANH:
110  post("x-fade fade-function: tangens hyperbolicus");
111  break;
112 
113  case Properties::SQRT:
114  post("x-fade fade-function: square root");
115  break;
116 
117  case Properties::LOG:
118  post("x-fade fade-function: logarithm");
119  break;
120 
121  case Properties::SIGMOID:
122  post("x-fade fade-function: Sigmoid");
123  break;
124  }
125  }
126 }
127 
128 // reset and initialize fade tbl to appropriate fade function.
129 // This will resize the fadetbl_ vector
130 void CrossFadeQueue::computeFadeTbl()
131 {
132  fadeTbl_.resize(fadeLength_);
133  double i = 0.0;
134  int tableIdx;
135  // double k = 0.0;
136  //int experiment = 64;
137 
138  // parameter for the tanh-fade function
139 
140  double b = 0.5;
141  double width = 0.9;
142  double a = log(7.)/width;
143  double f0=tanh(a*(-b));
144  double f1=tanh(a*(1-b));
145  // This will never be division by zero, due to the fact that we always have width > 0
146  double alpha = 1/(f1-f0);
147  double beta = f0;
148 
149  critical_enter(0); //making the creation of the table threadsafe
150  switch(fadeType_)
151  {
152  case Properties::COS: //cosine
153  //for (i = 0.0, tableIdx = 0; tableIdx < fadeLength_; i += (double) (kTTHalfPi / (fadeLength_ - 1)), tableIdx++) //kTTHalfPi was M_PI_2
154  //fadeTbl_[tableIdx] = (double) cos(i); // read forward to fade out, backward to fade in
155  for (i = 0.0, tableIdx = 0; tableIdx < fadeLength_; i += (double) (kTTPi / (fadeLength_ - 1)), tableIdx++) //kTTHalfPi was M_PI_2
156  {//post("last i %f",i);
157  fadeTbl_[tableIdx] = (double) 0.5*(1.0 + cos(i)); // read forward to fade out, backward to fade in
158  }
159  break;
160 
161  case Properties::COS_SQUARED: //cosine squared
162  //for (i = 0.0, tableIdx = 0; tableIdx < fadeLength_; i += (double) (kTTHalfPi / (fadeLength_ - 1)), tableIdx++) //kTTHalfPi was M_PI_2
163  // fadeTbl_[tableIdx] = (double) pow(cos(i),2.0); // read forward to fade out, backward to fade in
164  for (i = 0.0, tableIdx = 0; tableIdx < fadeLength_; i += (double) (1.0 / (fadeLength_ -1)), tableIdx++) //kTTHalfPi was M_PI_2
165  {//post("last i %f",i);
166  fadeTbl_[tableIdx] = (double) (1.0 + cos(i*i*kTTPi))*0.5; // read forward to fade out, backward to fade in
167  }
168  break;
169 
170  case Properties::LINEAR: //linear
171  for (i = 1.0, tableIdx = 0; tableIdx < fadeLength_; i -= (double) (1.0 / (fadeLength_ -1)), tableIdx++)
172  {//post("last i %f",i);
173  fadeTbl_[tableIdx] = (double) i; // read forward to fade out, backward to fade in
174  }
175  break;
176 
177  case Properties::TANH: //tanh-function
178  for (i = 1.0, tableIdx = 0; tableIdx < fadeLength_; i -= (double) (1.0 / (fadeLength_ -1)), tableIdx++)
179  {//post("last i %f",i);
180  fadeTbl_[tableIdx] = (double) alpha*(tanh(a*(i-b)) - beta);// read forward to fade out, backward to fade in
181  }
182  break;
183 
184  case Properties::LOG: //log-function
185  {
186  for (i = 1.0, tableIdx = 0; tableIdx < fadeLength_; i -= (double) (1.0 / (fadeLength_ )), tableIdx++)
187  { //post("last i %f",i);
188  fadeTbl_[tableIdx] = (double) 20*log10((i)*pow(10.0,((1-i)*0.05)));// read forward to fade out, backward to fade in
189  }
190  double temp = -1.0 * fadeTbl_[fadeLength_ -1];
191  for (tableIdx = 0; tableIdx < fadeLength_; tableIdx++)
192  fadeTbl_[tableIdx] = (fadeTbl_[tableIdx]+temp)/(temp);
193  }
194  break;
195 
196  case Properties::SIGMOID: //sigmoid function 1/(1+exp(t))
197  //double temp = -8;
198  //double tempk = temp * -2.0;
199  for (i = -8.0, tableIdx = 0; tableIdx < fadeLength_; i += (double) (16.0 / (fadeLength_- 1)), tableIdx++)
200  {//post("last i %f",i);
201  fadeTbl_[tableIdx] = (double) 1.0 / (1.0 + exp(i));// read forward to fade out, backward to fade in
202  }
203  break;
204  /*if (fadeLength_ >= experiment)
205  {
206 
207  for (i = 1.0, tableIdx = 0; tableIdx < experiment; i -= (double) (1.0 / (experiment)), tableIdx++)
208  fadeTbl_[tableIdx] = i;
209  for (tableIdx = experiment; tableIdx < fadeLength_; tableIdx++)
210  fadeTbl_[tableIdx] = 0.0f;
211  } */
212  //for (i = 0, tableIdx = 0; tableIdx < fadeLength_; i -= (double) (9.0 / (fadeLength_)), tableIdx++)
213  // fadeTbl_[tableIdx] = log10(i); // read forward to fade out, backward to fade in
214  //break;
215 
216  case Properties::SQRT: //square root
217  for (i = 1.0, tableIdx = 0; tableIdx < fadeLength_; i -= (double) (1.0 / (fadeLength_ - 1)), tableIdx++)
218  {//post("last i %f",i);
219  fadeTbl_[tableIdx] = sqrt(i); // read forward to fade out, backward to fade in
220  }
221  break;
222 
223  }
224  critical_exit(0);
225  if (fadeType_ != Properties::SIGMOID)
226  fadeTbl_[fadeLength_ - 1] = 0.0; // last value == 0.0
227 
228  if (globReportFlag)
229  {
230  for (tableIdx = 0; tableIdx < fadeLength_; tableIdx++)
231  post("Fade[%d]: %f", tableIdx, fadeTbl_[tableIdx]);
232  }
233 }
234 
235 // update individual CrossFades with new fadelength
236 void CrossFadeQueue::notifyCrossFades()
237 {
238  if (changed_)
239  {
240  for (std::deque< CrossFade *>::iterator iter = fadeQueue_.begin(); iter != fadeQueue_.end(); ++iter)
241  (*iter)->update(fadeLength_);
242  }
243 }
244 
245 // add new crossfade to queue, which has a pointer to this, returns true if started
247 {
248 
249  /*if (fadeQueue_.size() >= 3) // destroy oldest inactive (2nd to front) element, shift up queue.
250  {
251  // start at end of queue (back)
252  std::deque<CrossFade*>::iterator iter = fadeQueue_.begin();
253  iter++; // get element before front
254  fadeQueue_.erase(iter); // erase this element
255  }*/
256 
257  if (!isActive()) // if empty
258  {
259  fadeQueue_.push_back(new CrossFade(*this)); // enqueue new crossfade
260 
261  /*
262  // swap new and old filter sets if at start of fade
263  for (int i = 0; i < 3; i++)
264  {
265  int temp = oldFilterIdx[i];
266  oldFilterIdx[i] = newFilterIdx[i];
267  newFilterIdx[i] = temp;
268  }*/
269 
270  if (globReportFlag)
271  post("new crossfade added, total crossfades = %d", fadeQueue_.size());
272  return true;
273  }
274  else
275  return false;
276 }
277 
279 {
280  return fadeQueue_.size();
281 }
282 
284 {
285  return fadeThreshold_;
286 }
287 
288 void CrossFadeQueue::fadeThreshold(long newThreshold)
289 {
290  if (newThreshold >= 1)
291  fadeThreshold_ = newThreshold;
292  else if (globWarningFlag)
293  error("Invalid crossfade threshold %ld, must be >= 1", newThreshold);
294 
295  if (globReportFlag)
296  post("Crossfade threshold in samples: %d", fadeThreshold_);
297 }
298 
300 {
301  assert(isActive()); // make sure there's an element on the queue
302  delete fadeQueue_.front();
303  fadeQueue_.pop_front();
304 }
305 
307 {
308  fadeQueue_.front()->increment();
309 }
310 
312 {
313  return !fadeQueue_.empty();
314 }
315 
316 double CrossFadeQueue::tick(double fadeInInput, double fadeOutInput)
317 {
318  return fadeQueue_.front()->tick(fadeInInput, fadeOutInput);
319 }
320 
321 // tells caller if crossfade is at beginning or not
323 {
324  if (isActive())
325  {
326  return fadeQueue_.front()->atStart();
327  }
328  else
329  return false;
330 }
331 
332 // vim:sw=4:et:cindent:
long fadeThreshold() const
Get fade threshold in samples.
bool atStart() const
True if at beginning of crossfade.
~CrossFadeQueue()
Class destructor.
bool isActive() const
True if a crossfade is underway, false othewise.
void fadeFunction(Properties::fadeMode fadeType)
Set fade type (LINEAR, COS, COS_SQUARED, TANH, SQRT, LOG, SIGMOID)
CrossFadeQueue(long fadeThreshold, long fadeLength, Properties::fadeMode fadeType, double sampleRate)
CrossFade class.
Definition: CrossFade.h:21
Jamoma's lowest-level base class and related infrastructure.
double fadeLength() const
Get fade time in samples.
bool startFade()
Triggers a crossfade, returns true if fade has started.
double getTblValAt(int index) const
Returns crossfade table value at given index.
void increment()
Increment top level crossfade.
void finishFade()
Manages cleanup and end of crossfade.
TTFOUNDATION_EXPORT const TTFloat64 kTTPi
[doxygenAppendixC_constExample]
Definition: TTBase.cpp:23
int size()
Return number of crossfades being queued.
double tick(double fadeInInput, double fadeOutInput)
Out value of crossfade.