CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

Envelope.cpp
Go to the documentation of this file.
1 //
2 // Envelope.cpp -- Implementation of LineSegment and Envelope classes
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5
6 #include "Envelope.h"
7 #include <stdlib.h>
8 #include <iostream>
9 #include <math.h>
10
11 //#define CSL_DEBUG
12
13 using namespace csl;
14
15 /// LineSegment class
16
17 /// Constructors
18
19 LineSegment::LineSegment() :
20 UnitGenerator(), mMode(kLine), mCurrentValue(0), mCurrentFrame(0) { }
21
22 LineSegment::LineSegment(float d, float s, float e, LineMode mode) :
23 UnitGenerator(),
24 mStart(s), mEnd(e), mDuration(d), mMode(mode), mCurrentValue(s), mCurrentFrame(0) {
25 if (mode == kExpon) {
26 if (mStart == 0) {
27 mStart = 0.00001f; // Arbitrary small value.
28 // logMsg("Start value can't be '0' for exponential segments. Corrected to be 0.00001.");
29 }
30 if (mEnd == 0) {
31 mEnd = 0.00001f;
32 // logMsg("End value can't be '0' for exponential segments. Corrected to be 0.00001.");
33 }
34 }
35 }
36
37 /// Reset method
38
39 void LineSegment::reset(){
40 mCurrentValue = mStart;
41 mCurrentFrame = 0;
42 }
43
44 void LineSegment::dump() {
45 logMsg("\tLineSegment: %g to %g in %g (%s)", mStart, mEnd, mDuration,
46 (mMode == kLine ? "linear" : "exponential"));
47 }
48
49 void LineSegment::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException) {
50 nextBuffer(outputBuffer, outBufNum, 0, 0);
51 }
52
53 void LineSegment::nextBuffer(Buffer &outputBuffer, unsigned outBufNum, Port * scalePort, Port * offsetPort)
54 throw (CException) {
55 unsigned i;
56 float rate = (float) mFrameRate;
57 unsigned numFrames = outputBuffer.mNumFrames;
58 SampleBuffer outPtr = outputBuffer.buffer(outBufNum);
59 float scaleValue = 1, offsetValue = 0; // used for dynamic input;
60
61 /// calculate the increment for the linear interpolation, the number of frames to calculate
62 /// and the number of frames that are constant (at the end of the interpolations)
63 unsigned numFramesToCalc = (int)(mDuration * rate) - mCurrentFrame;
64 unsigned constantFrames;
65
66 /// This test to see if we're at the end works for now, but we should use a bool to check if we are done
67 /// in case mCurrentFrame loops
68 if (numFramesToCalc <= 0) {
69 numFramesToCalc = 0;
70 constantFrames = numFrames;
71 mCurrentValue = mEnd;
72 } else {
73 if (numFramesToCalc > numFrames)
74 numFramesToCalc = numFrames;
75 constantFrames = numFrames - numFramesToCalc;
76 }
77 float currentValue = mCurrentValue;
78 float increment;
79 #ifdef CSL_DEBUG
80 // logMsg("LineSegment nextBuffer");
81 #endif
82 switch(mMode) {
83 case kLine:
84 increment = (mEnd - mStart) / (mDuration * rate);
85 for (i = 0; i < numFramesToCalc; i++) { ///< Generate the interpolated frames
86 CHECK_UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
87 *outPtr++ = (currentValue * scaleValue) + offsetValue;
88 currentValue += increment;
89 }
90 break;
91 case kExpon:
92 increment = pow(mEnd / mStart, 1/(mDuration * rate));
93 for (i = 0; i < numFramesToCalc; i++) { ///< Generate the interpolated frames
94 CHECK_UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
95 *outPtr++ = (currentValue * scaleValue) + offsetValue;
96 currentValue *= increment;
97 }
98 break;
99 default:
100 break;
101 }
102 for (i = 0; i < constantFrames; i++) { ///< Generate the constant frames
103 CHECK_UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
104 *outPtr++ = (mEnd * scaleValue) + offsetValue;
105 }
106 if (mCurrentValue != mEnd) {
107 mCurrentFrame += numFrames; ///< if we're not already at the end increment my internal counters
108 mCurrentValue = currentValue;
109 }
110 // fprintf(stderr, " _%5.3f_ ", (currentValue * scaleValue) + offsetValue);
111 }
112
113 /// Envelope class
114
115 /// Lots of useful constructors
116
117 Envelope::Envelope(LineMode mode, float t, float x1, float y1, float x2, float y2, float x3, float y3,
118 float x4, float y4, float x5, float y5, float x6, float y6)
119 : UnitGenerator(), Scalable(1, 0), mDuration(t) {
120 mSegmentMap[x1] = new LineSegment(0, 0, y1, mode);
121 if (x2 != 0) mSegmentMap[x2] = new LineSegment(0, 0, y2, mode);
122 if (x3 != 0) mSegmentMap[x3] = new LineSegment(0, 0, y3, mode);
123 if (x4 != 0) mSegmentMap[x4] = new LineSegment(0, 0, y4, mode);
124 if (x5 != 0) mSegmentMap[x5] = new LineSegment(0, 0, y5, mode);
125 if (x6 != 0) mSegmentMap[x6] = new LineSegment(0, 0, y6, mode);
126 this->createSegments();
127 }
128
129 Envelope::Envelope(LineMode mode, float t, unsigned int size, float x[], float y[])
130 : UnitGenerator(), Scalable(1, 0), mDuration(t) {
131 for (unsigned int i = 0; i < size; i++)
132 mSegmentMap[x[i]] = new LineSegment(0, 0, y[i], mode);
133 this->createSegments();
134 }
135
136 Envelope::Envelope(float t, float x1, float y1, float x2, float y2, float x3, float y3,
137 float x4, float y4, float x5, float y5, float x6, float y6)
138 : UnitGenerator(), Scalable(1.0f, 0.0f), mDuration(t) {
139 mSegmentMap[x1] = new LineSegment(0, 0, y1);
140 if (x2 != 0) mSegmentMap[x2] = new LineSegment(0, 0, y2);
141 if (x3 != 0) mSegmentMap[x3] = new LineSegment(0, 0, y3);
142 if (x4 != 0) mSegmentMap[x4] = new LineSegment(0, 0, y4);
143 if (x5 != 0) mSegmentMap[x5] = new LineSegment(0, 0, y5);
144 if (x6 != 0) mSegmentMap[x6] = new LineSegment(0, 0, y6);
145 this->createSegments();
146 }
147
148 Envelope::Envelope(float t, unsigned int size, float x[], float y[])
149 : UnitGenerator(), Scalable(1, 0), mDuration(t) {
150 for (unsigned int i = 0; i < size; i++)
151 mSegmentMap[x[i]] = new LineSegment(0, 0, y[i]);
152 this->createSegments();
153 }
154
155 Envelope::~Envelope() {
156 for (unsigned i = 0; i < mSegmentMap.size(); ++i)
157 delete mSegments[i];
158 if (mValues)
159 delete[] mValues;
160 if (mSegments)
161 free(mSegments);
162 }
163
164 void Envelope::createSegments() {
165 mValues = new float[mSegmentMap.size()];
166 mSegments = (LineSegment ** ) malloc(mSegmentMap.size() * (sizeof(char *)));
167 calculateSegments();
168 }
169
170 void Envelope::calculateSegments() {
171 unsigned i = 0;
172 mSize = mSegmentMap.size();
173 Breakpoints::iterator idx;
174 // The very first segment is not really used.
175 // The number of segments is always 1 less than the number of points.
176 for (idx = mSegmentMap.begin(); idx != mSegmentMap.end(); ++idx) {
177 mValues[i] = idx->first;
178 mSegments[i] = idx->second;
179 i++;
180 }
181 mSegments[0]->setStart(mSegments[0]->end());
182 mSegments[0]->setDuration(float(mValues[0]));
183 for (i = 1; i < mSize; ++i) {
184 mSegments[i]->setStart(mSegments[i - 1]->end());
185 mSegments[i]->setDuration(float(mValues[i] - mValues[i - 1]));
186 }
187 mCurrentMark = mDuration; // set to end
188 }
189
190 /////////////////////// Operations ///////////////////////////////////
191
192 void Envelope::addBreakpoint(float startTime, float tvalue) {
193 mSegmentMap[startTime] = new LineSegment(0, 0, tvalue);
194 LineSegment **tempLinsegPtr = mSegments;
195 float *tempPtr = mValues;
196
197 this->createSegments();
198 if (startTime > mDuration)
199 mDuration = startTime;
200 if (tempPtr)
201 delete[] tempPtr;
202 if (tempLinsegPtr)
203 free(tempLinsegPtr);
204 }
205
206 void Envelope::setMode(LineMode mode) {
207 for (unsigned i = 0; i < mSize; i++)
208 mSegments[i]->setMode(mode);
209 }
210
211 bool Envelope::isActive() {
212 // float diff = mCurrentMark - mDuration;
213 // if ((diff > 0.0) && (diff < 0.1))
214 // fprintf(stderr, " %5.4f = %s\n", diff, (mCurrentMark < mDuration) ? "true" : "false");
215 return (mCurrentMark < mDuration);
216 }
217
218 /// Scaling operations
219
220 void Envelope::setDuration(float d) {
221 //if ((mDuration == 0.0f) || (! isnormal(mDuration))) {
222 if (mDuration == 0.0f) {
223 logMsg(kLogError, "Impossible env dur");
224 throw RunTimeError("Impossible env dur");
225 }
226 this->scaleTimes(d / mDuration);
227 }
228
229 void Envelope::scaleTimes(float s) {
230 if (s != 1) {
231 for (unsigned i = 0; i < mSize; ++i) {
232 mSegmentMap.erase(mValues[i]); // Erase old values.
233 mValues[i] *= s; // update the stored values to the new scaled ones.
234 }
235 for (unsigned i = 0; i < mSize; ++i) {
236 mSegmentMap[mValues[i]] = mSegments[i]; // Add the new values to the map
237 mSegments[i]->reset(); // Reset all segments.
238 }
239 }
240 mDuration *= s;
241 calculateSegments();
242 }
243
244 // scale values so that the env's max is s
245
246 void Envelope::scaleValues(float s) {
247 float maxV = 0.0f;
248 for (unsigned i = 0; i < mSize; ++i) {
249 LineSegment * seg = mSegments[i];
250 if (seg->start() > maxV) maxV = seg->start();
251 if (seg->end() > maxV) maxV = seg->end();
252 }
253 float scale = s / maxV;
254 for (unsigned i = 0; i < mSize; ++i) {
255 LineSegment * seg = mSegments[i];
256 seg->setStart(seg->start() * scale);
257 seg->setEnd(seg->end() * scale);
258 }
259 }
260
261 /// Pretty-printer
262
263 void Envelope::dump() {
264 logMsg("Envelope Duration = %g", mDuration);
265 fprintf(stderr, "\tat 0 seconds \t\t");
266 mSegments[0]->dump();
267 for (unsigned i = 1; i < mSize; i++) {
268 fprintf(stderr, "\tat %g seconds \t\t", mValues[i-1]);
269 mSegments[i]->dump();
270 }
271 Scalable::dump();
272 }
273
274 /// Reset time to 0.0 to restart envelope
275
276 void Envelope::reset() {
277 mCurrentMark = 0.0f;
278 for (unsigned i = 0; i < mSize; ++i)
279 mSegments[i]->reset();
280 }
281
282 // trigger means reset
283
284 void Envelope::trigger() {
285 reset();
286 }
287
288 //
289 // Next buffer calculation -- Here's where the work gets done
290 //
291
292 void Envelope::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException) {
293 SampleBuffer outPtr = outputBuffer.buffer(outBufNum);
294 unsigned numFrames = outputBuffer.mNumFrames;
295 unsigned i, tempFrames;
296 float rate = mFrameRate;
297 float endMark, x;
298 DECLARE_SCALABLE_CONTROLS; // declare the scale/offset buffers and values
299 #ifdef CSL_DEBUG
300 // logMsg("Envelope nextBuffer");
301 #endif
302 LOAD_SCALABLE_CONTROLS; // load the scaleC and offsetC from the constant or dynamic value
303 // if the envelope is finished, just write the final value into the buffer
304 if (mCurrentMark >= mDuration) {
305 x = mSegments[mSize - 1]->end(); // mPoints[mSize - 1]->y;
306 for (i = 0; i < numFrames; i++) {
307 *outPtr++ = (x * scaleValue) + offsetValue;
308 UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
309 }
310 return;
311 } // find out what segment we're in and let the segment fill the buffer
312 // if (mCurrentMark < mValues[0]) {
313 //
314 // }
315 for (i = 0; i < mSize; ++i) {
316 x = mValues[i];
317 if (mCurrentMark < x) {
318 endMark = mCurrentMark + ((float)numFrames / rate);
319 if (endMark < x) { // if the current next_buffer request all falls into one line segment
320 mSegments[i]->nextBuffer(outputBuffer, outBufNum, scalePort, offsetPort);
321 mCurrentMark += ((float) (numFrames + 1) / rate);
322 // fprintf(stderr, "E: %5.3f", *outPtr);
323 return;
324 } else { // if the current next_buffer request spans line segments, go
325 // to the end of this line segment and call nextBuffer again
326 #ifdef CSL_DEBUG
327 logMsg("\t\tEnvelope crossing: current mark: %g point: %g @ %g ls: %g to %g in %g",
328 mCurrentMark, mValues[i], mSegments[i]->end(),
329 mSegments[i]->start(), mSegments[i]->end(), mSegments[i]->duration());
330 #endif
331 tempFrames = (unsigned) ((mValues[i] - mCurrentMark) * rate);
332 outputBuffer.mNumFrames = tempFrames;
333 // get the first segment
334 mSegments[i]->nextBuffer(outputBuffer, outBufNum, scalePort, offsetPort);
335
336 // update pointers
337 mCurrentMark += ((float) (numFrames + 1) / rate);
338 outputBuffer.setBuffer(outBufNum, outputBuffer.buffer(outBufNum) + tempFrames);
339 outputBuffer.mNumFrames = numFrames - tempFrames;
340 // call myself recursively
341 this->nextBuffer(outputBuffer, outBufNum);
342 // clean up
343 mCurrentMark += ((float) (numFrames + 1) / rate);
344 outputBuffer.setBuffer(outBufNum, outPtr);
345 outputBuffer.mNumFrames = numFrames;
346 if (i == (mSize - 1)) {
347 #ifdef CSL_DEBUG
348 logMsg("Envelope finished");
349 #endif
350 mCurrentMark = mDuration;
351 }
352 return;
353 }
354 }
355 }
356 logMsg(kLogError, "Envelope nextBuffer: it shouldn't get here %f", rate);
357 this->dump();
358 return; // shouldn't ever get here (THROW AN EXCEPTION IF CONTROL GETS HERE!)
359 }
360
361 /// ~~~~~~~ Atack / Decay / Sustain / Release Envelope ~~~~~~~~~~~
362
363 /// Minimal version - ADSR . . . call the Super constructor, passing the appropriate points.
364
365 ADSR::ADSR(LineMode mode, float t, float a, float d, float s, float r)
366 : Envelope(mode, t, 0.0, 0.0, a, 1.0, a + d, s, t - r, s, t, 0.0) { };
367
368 /// with initial delay - IADSR
369
370 ADSR::ADSR(LineMode mode, float t, float i, float a, float d, float s, float r)
371 : Envelope(mode, t, i, 0.0, i + a, 1.0, i + a + d, s, t - r, s, t, 0.0) { };
372
373 /// Minimal version - ADSR . . . call the Super constructor, passing the appropriate points.
374
375 ADSR::ADSR(float t, float a, float d, float s, float r)
376 : Envelope(t, 0.0, 0.0, a, 1.0, a + d, s, t - r, s, t, 0.0) { };
377
378 /// with initial delay - IADSR
379
380 ADSR::ADSR(float t, float i, float a, float d, float s, float r)
381 : Envelope(t, i, 0.0, i + a, 1.0, i + a + d, s, t - r, s, t, 0.0) { };
382
383 /// Operations --
384
385 void ADSR::setDuration(float d) {
386 // if (d <= mValues[3])
387 Envelope::setDuration(d);
388 // else {
389 // this->dump();
390 // float oldD = mDuration - mValues[3];
391 // mDuration = d;
392 // mSegmentMap[mDuration - oldD] = mSegmentMap[mValues[3]];
393 // mSegmentMap.erase(mValues[3]);
394 // this->calculateSegments();
395 // this->dump();
396 // }
397 }
398
399 void ADSR::setDelay(float del) {
400 mSegmentMap[del] = mSegmentMap[mValues[0]]; // Add a new "initial delay key" and then remove the old one.
401 mSegmentMap[del + mSegments[1]->duration()] = mSegmentMap[mValues[1]]; // update the value of the next
402 if (mValues[0] != del) { // If value is different, then erase the old value.
403 mSegmentMap.erase(mValues[0]);
404 mSegmentMap.erase(mValues[1]);
405 }
406 this->calculateSegments();
407 }
408
409 void ADSR::setAttack(float attack) {
410 mSegmentMap[mValues[0] + attack] = mSegmentMap[mValues[1]]; // Add a new "attack key" and then remove the old one.
411 mSegmentMap[mValues[0] + attack + mSegments[2]->duration()] = mSegmentMap[mValues[2]]; // update the value of the next
412 if (mValues[1] != mValues[0] + attack) { // If value is different, then erase the old value.
413 mSegmentMap.erase(mValues[1]);
414 mSegmentMap.erase(mValues[2]);
415 }
416 this->calculateSegments();
417 }
418
419 void ADSR::setDecay(float decay) {
420 mSegmentMap[mValues[1] + decay] = mSegmentMap[mValues[2]];
421 if (mValues[2] != mValues[1] + decay)
422 mSegmentMap.erase(mValues[2]);
423 this->calculateSegments();
424 }
425
426 void ADSR::setSustain(float sustain) {
427 mSegments[2]->setEnd(sustain);
428 mSegments[3]->setEnd(sustain);
429 this->calculateSegments();
430 }
431
432 void ADSR::setRelease(float trelease) {
433 mSegmentMap[mDuration - trelease] = mSegmentMap[mValues[3]];
434 if (mValues[3] != mDuration - trelease)
435 mSegmentMap.erase(mValues[3]);
436 this->calculateSegments();
437 }
438
439 // Trigger the release segment
440
441 void ADSR::release(void) {
442 mCurrentMark = mValues[3];
443 }
444
445 /// ~~~~~~~ Atack / Release Envelope ~~~~~~~~~~~
446
447 /// Minimal version - AR
448
449 AR::AR(LineMode mode, float t, float a, float r)
450 : Envelope(mode, t, 0.0, 0.0, a, 1.0, t - r, 1.0, t, 0.0) { };
451
452 /// with initial delay - I-AR
453
454 AR::AR(LineMode mode, float t, float i, float a, float r)
455 : Envelope(mode, t, i, 0.0, i + a, 1.0, t - r, 1.0, t, 0.0) { };
456
457 /// Minimal version - AR
458
459 AR::AR(float t, float a, float r)
460 : Envelope(t, 0.0, 0.0, a, 1.0, t - r, 1.0, t, 0.0) { };
461
462 /// with initial delay - I-AR
463
464 AR::AR(float t, float i, float a, float r)
465 : Envelope(t, i, 0.0, i + a, 1.0, t - r, 1.0, t, 0.0) { };
466
467 /// Operations
468
469 void AR::setDuration(float d) {
470 // if (d <= mValues[2])
471 Envelope::setDuration(d);
472 // else {
473 // float oldD = mDuration - mValues[2];
474 // mDuration = d;
475 // mSegmentMap[mDuration - oldD] = mSegmentMap[mValues[2]];
476 // mSegmentMap.erase(mValues[2]);
477 // this->calculateSegments();
478 // }
479 }
480
481 void AR::setDelay(float del) {
482 mSegmentMap[del] = mSegmentMap[mValues[0]];
483 if (mValues[0] != del) // If value is different, then erase the old value.
484 mSegmentMap.erase(mValues[0]);
485 this->calculateSegments();
486 }
487
488 void AR::setAttack(float attack) {
489 mSegmentMap[mValues[0] + attack] = mSegmentMap[mValues[1]];
490 if (mValues[1] != mValues[0] + attack) // If value is different, then erase the old value.
491 mSegmentMap.erase(mValues[1]);
492 this->calculateSegments();
493 }
494
495 void AR::setRelease(float trelease) {
496 mSegmentMap[mDuration - trelease] = mSegmentMap[mValues[2]];
497 if (mValues[2] != mDuration - trelease)
498 mSegmentMap.erase(mValues[2]);
499 this->calculateSegments();
500 }
501
502 void AR::setAll(float d, float a, float r) {
503 mDuration = d;
504 mSegmentMap[mValues[0] + a] = mSegmentMap[mValues[1]];
505 mSegmentMap[mDuration - r] = mSegmentMap[mValues[2]];
506 mSegmentMap[mDuration] = mSegmentMap[mValues[3]];
507 if (mValues[2] != a) mSegmentMap.erase(mValues[1]);
508 if (mValues[3] != r) mSegmentMap.erase(mValues[2]);
509 if (mValues[4] != d) mSegmentMap.erase(mValues[3]);
510
511 this->calculateSegments();
512 }
513
514 /// trigger the release segment
515
516 void AR::release(void) {
517 mCurrentMark = mValues[2];
518 }
519
520
521 /// ~~~~~ Triangle class ~~~~~
522
523 // simple constructor
524
525 Triangle::Triangle(LineMode mode, float t, float a)
526 : Envelope(mode, t, 0.0, 0.0, t/2, a, t, 0.0) { }
527
528 // versions with initial delay segments
529
530 Triangle::Triangle(LineMode mode, float t, float i, float a)
531 : Envelope(mode, t, i, 0.0, (t-i)/2, a, t, 0.0) { }
532
533 // simple constructor
534
535 Triangle::Triangle(float t, float a)
536 : Envelope(t, 0.0, 0.0, t/2, a, t, 0.0) { }
537
538 // versions with initial delay segments
539
540 Triangle::Triangle(float t, float i, float a)
541 : Envelope(t, i, 0.0, (t-i)/2, a, t, 0.0) { }
542
543
544 /// ~~~~~~~~ RandEnvelope envelope class ~~~~~~~
545
546 // Constructors
547
548 RandEnvelope::RandEnvelope(float frequency, float amplitude, float offset, float step)
549 : Envelope(), mFrequency(frequency), mAmplitude(amplitude),
550 mStep(step), mOffset(offset), mWalk(false) {
551 mSize = 0;
552 if (mStep == 0)
553 mStep = mAmplitude / 2.0;
554 initSegment();
555 mValues = 0;
556 mSegments = 0;
557 }
558
559 // Prepare by putting an ending value in the line segment
560
561 void RandEnvelope::initSegment() {
562 mLastVal = fRandZ() * 2.0 - 1.0;
563 mSegment.setEnd(mLastVal * mAmplitude + mOffset);
564 nextSegment();
565 }
566
567 // To choose the next segment
568
569 void RandEnvelope::nextSegment() {
570 float next = 0.0f, randVal;
571 mSegment.setStart(mSegment.end());
572 if ( ! mWalk) { // pick a new random and constrain it to the proper range
573 randVal = (fRandZ() * 2.0 - 1.0) * (mStep / mAmplitude);
574 next = mLastVal + randVal;
575 if (next > 1.0)
576 next = mLastVal - randVal;
577 if (next < -1.0)
578 next = mLastVal + randVal;
579 mLastVal = next;
580 next = next * mAmplitude + mOffset;
581 // logMsg("RE %5.3f\n", next);
582 } else {
583 // what to do here?
584 }
585 mSegment.setEnd(next);
586 mSegment.setDuration((float) (1.0 / mFrequency));
587 mSegment.reset();
588 mCurrentIndex = 0;
589 mSegmentLength = (unsigned) (mSegment.duration() * mFrameRate);
590 }
591
592 // NextBuffer for rand
593
594 void RandEnvelope::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException) {
595 SampleBuffer outPtr = outputBuffer.buffer(outBufNum);
596 unsigned numFrames = outputBuffer.mNumFrames;
597 unsigned endMark = mCurrentIndex + numFrames;
598 DECLARE_SCALABLE_CONTROLS; // declare the scale/offset buffers and values
599
600 // if we can answer the request with the current line segment...
601 if (endMark < mSegmentLength) {
602 mSegment.nextBuffer(outputBuffer, outBufNum, scalePort, offsetPort);
603 mCurrentIndex += numFrames;
604 return;
605 }
606 // else, do some, then create update the line segment
607 unsigned tempFrames = mSegmentLength - mCurrentIndex;
608 outputBuffer.mNumFrames = tempFrames;
609 mSegment.nextBuffer(outputBuffer, outBufNum, scalePort, offsetPort);
610 // update pointers
611 nextSegment();
612 outputBuffer.setBuffer(outBufNum, outputBuffer.buffer(outBufNum) + tempFrames);
613 outputBuffer.mNumFrames = numFrames - tempFrames;
614 // call the next line segment (must be long enough to fill the buffer)
615 mSegment.nextBuffer(outputBuffer, outBufNum, scalePort, offsetPort);
616 // clean up
617 mCurrentIndex = numFrames - tempFrames;
618 outputBuffer.setBuffer(outBufNum, outPtr);
619 outputBuffer.mNumFrames = numFrames;
620 return;
621 }