blob: 89ab2bee3cb24954d2280796bf6591476ac97df8 [file] [log] [blame]
The Android Open Source Project2729ea92008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "ToneGenerator"
19#include <utils/threads.h>
20
21#include <stdio.h>
22#include <math.h>
23#include <utils/Log.h>
24#include <sys/resource.h>
25#include <utils/RefBase.h>
26#include <utils/Timers.h>
27#include "media/ToneGenerator.h"
28
29namespace android {
30
31// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
32const ToneGenerator::ToneDescriptor
33 ToneGenerator::toneDescriptors[NUM_TONES] = {
34 // waveFreq[] segments[] repeatCnt
35 { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0
36 { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1
37 { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2
38 { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3
39 { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4
40 { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5
41 { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6
42 { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7
43 { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8
44 { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9
45 { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S
46 { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P
47 { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A
48 { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B
49 { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C
50 { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D
51 { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL
52 { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY
53 { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION
54 { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK
55 { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL
56 { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
57 { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
58 { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
59 { { 400, 1200, 0 }, { 35, 0 }, 0 }, // TONE_PROP_BEEP
60 { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
61 { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
62 { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
63 { { 400, 1200, 0 }, { 35, 200, 35, 0 }, 0 } // TONE_PROP_BEEP2
64 };
65
66////////////////////////////////////////////////////////////////////////////////
67// ToneGenerator class Implementation
68////////////////////////////////////////////////////////////////////////////////
69
70
71//---------------------------------- public methods ----------------------------
72
73
74////////////////////////////////////////////////////////////////////////////////
75//
76// Method: ToneGenerator::ToneGenerator()
77//
78// Description: Constructor. Initializes the tone sequencer, intantiates required sine wave
79// generators, instantiates output audio track.
80//
81// Input:
82// toneType: Type of tone generated (values in enum tone_type)
83// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type)
84// volume: volume applied to tone (0.0 to 1.0)
85//
86// Output:
87// none
88//
89////////////////////////////////////////////////////////////////////////////////
90ToneGenerator::ToneGenerator(int streamType, float volume) {
91 const sp<IAudioFlinger>& lpAudioFlinger = AudioSystem::get_audio_flinger();
92
93 LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
94
95 mState = TONE_IDLE;
96 mpAudioTrack = 0;
97 mpToneDesc = 0;
98 mpNewToneDesc = 0;
99
100 if (lpAudioFlinger == 0) {
101 LOGE("Unable to marshal AudioFlinger");
102 goto ToneGenerator_exit;
103 }
104
105 mSamplingRate = lpAudioFlinger->sampleRate();
106
107 mVolume = volume;
108 // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers
109 mpAudioTrack
110 = new AudioTrack(streamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS, 0, audioCallback, this);
111
112 if (mpAudioTrack == 0) {
113 LOGE("AudioTrack allocation failed");
114 goto ToneGenerator_exit;
115 }
116 LOGV("Create Track: %p\n", mpAudioTrack);
117
118 if (mpAudioTrack->initCheck() != NO_ERROR) {
119 LOGE("AudioTrack->initCheck failed");
120 goto ToneGenerator_exit;
121 }
122
123 mpAudioTrack->setVolume(volume, volume);
124
125 LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
126
127 mState = TONE_INIT;
128
129 return;
130
131ToneGenerator_exit:
132
133 // Cleanup
134 if (mpAudioTrack) {
135 LOGV("Delete Track I: %p\n", mpAudioTrack);
136 delete mpAudioTrack;
137 }
138
139 LOGV("!!!ToneGenerator INIT FAILED!!!\n");
140}
141
142////////////////////////////////////////////////////////////////////////////////
143//
144// Method: ToneGenerator::~ToneGenerator()
145//
146// Description: Destructor. Stop sound playback and delete audio track if
147// needed and delete sine wave generators.
148//
149// Input:
150// none
151//
152// Output:
153// none
154//
155////////////////////////////////////////////////////////////////////////////////
156ToneGenerator::~ToneGenerator() {
157 LOGV("ToneGenerator destructor\n");
158
159 if (mpAudioTrack) {
160 stopTone();
161 LOGV("Delete Track: %p\n", mpAudioTrack);
162 delete mpAudioTrack;
163 }
164}
165
166////////////////////////////////////////////////////////////////////////////////
167//
168// Method: ToneGenerator::startTone()
169//
170// Description: Starts tone playback.
171//
172// Input:
173// none
174//
175// Output:
176// none
177//
178////////////////////////////////////////////////////////////////////////////////
179bool ToneGenerator::startTone(int toneType) {
180 bool lResult = false;
181
182 if (mState == TONE_IDLE || toneType >= NUM_TONES)
183 return lResult;
184
185 LOGV("startTone\n");
186
187 mLock.lock();
188
189 // Get descriptor for requested tone
190 mpNewToneDesc = &toneDescriptors[toneType];
191
192 if (mState == TONE_INIT) {
193 if (prepareWave()) {
194 LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
195
196 mState = TONE_STARTING;
197 mLock.unlock();
198 mpAudioTrack->start();
199 mLock.lock();
200 if (mState == TONE_STARTING) {
201 if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR)
202 LOGE("--- timed out");
203 }
204
205 if (mState == TONE_PLAYING)
206 lResult = true;
207 }
208 } else {
209 LOGV("Delayed start\n");
210
211 mState = TONE_RESTARTING;
212 if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
213 if (mState != TONE_INIT) {
214 lResult = true;
215 }
216 LOGV("cond received");
217 } else {
218 LOGE("--- timed out");
219 }
220 }
221 mLock.unlock();
222
223 LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
224
225 return lResult;
226}
227
228////////////////////////////////////////////////////////////////////////////////
229//
230// Method: ToneGenerator::stopTone()
231//
232// Description: Stops tone playback.
233//
234// Input:
235// none
236//
237// Output:
238// none
239//
240////////////////////////////////////////////////////////////////////////////////
241void ToneGenerator::stopTone() {
242 LOGV("stopTone");
243
244 mLock.lock();
245 if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
246 mState = TONE_STOPPING;
247 LOGV("waiting cond");
248 status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
249 if (lStatus == NO_ERROR) {
250 LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
251 } else {
252 LOGE("--- timed out");
253 mState = TONE_INIT;
254 }
255 }
256
257 clearWaveGens();
258
259 mLock.unlock();
260}
261
262//---------------------------------- private methods ---------------------------
263
264
265////////////////////////////////////////////////////////////////////////////////
266//
267// Method: ToneGenerator::audioCallback()
268//
269// Description: AudioTrack callback implementation. Generates a block of
270// PCM samples
271// and manages tone generator sequencer: tones pulses, tone duration...
272//
273// Input:
274// user reference (pointer to our ToneGenerator)
275// info audio buffer descriptor
276//
277// Output:
278// returned value: always true.
279//
280////////////////////////////////////////////////////////////////////////////////
281void ToneGenerator::audioCallback(void* user, const AudioTrack::Buffer& info) {
282 ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
283 short *lpOut = info.i16;
284 unsigned int lReqSmp = info.size/sizeof(short);
285 unsigned int lGenSmp;
286 unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
287 bool lSignal = false;
288
289
290 lpToneGen->mLock.lock();
291
292 // Clear output buffer: WaveGenerator accumulates into lpOut buffer
293 memset(lpOut, 0, info.size);
294
295 // Update pcm frame count and end time (current time at the end of this process)
296 lpToneGen->mTotalSmp += lReqSmp;
297
298 // Update tone gen state machine and select wave gen command
299 switch (lpToneGen->mState) {
300 case TONE_PLAYING:
301 lWaveCmd = WaveGenerator::WAVEGEN_CONT;
302 break;
303 case TONE_STARTING:
304 LOGV("Starting Cbk");
305
306 lWaveCmd = WaveGenerator::WAVEGEN_START;
307 break;
308 case TONE_STOPPING:
309 case TONE_RESTARTING:
310 LOGV("Stop/restart Cbk");
311
312 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
313 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
314 break;
315 default:
316 LOGV("Extra Cbk");
317 goto audioCallback_Exit;
318 }
319
320 // Exit if to sequence is over
321 if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
322 goto audioCallback_Exit;
323 }
324
325 if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
326 // Time to go to next sequence segment
327
328 LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
329
330 lGenSmp = lReqSmp;
331
332 if (lpToneGen->mCurSegment & 0x0001) {
333 // If odd segment, OFF -> ON transition : reset wave generator
334 lWaveCmd = WaveGenerator::WAVEGEN_START;
335
336 LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
337 } else {
338 // If even segment, ON -> OFF transition : ramp volume down
339 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
340
341 LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
342 }
343
344 // Pre increment segment index and handle loop if last segment reached
345 if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
346 LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
347
348 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
349 if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
350 LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
351
352 lpToneGen->mCurSegment = 0;
353
354 LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
355 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
356
357 } else {
358 LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
359
360 // Cancel OFF->ON transition in case previous segment tone state was OFF
361 if (!(lpToneGen->mCurSegment & 0x0001)) {
362 lGenSmp = 0;
363 }
364 }
365 } else {
366 LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
367 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
368 }
369
370 // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
371 lpToneGen->mNextSegSmp
372 += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
373
374 } else {
375 // Inside a segment keep tone ON or OFF
376 if (lpToneGen->mCurSegment & 0x0001) {
377 lGenSmp = 0; // If odd segment, tone is currently OFF
378 } else {
379 lGenSmp = lReqSmp; // If event segment, tone is currently ON
380 }
381 }
382
383 if (lGenSmp) {
384 // If samples must be generated, call all active wave generators and acumulate waves in lpOut
385 unsigned int lWaveIdx;
386
387 for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
388 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
389 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
390 }
391 }
392
393audioCallback_Exit:
394
395 switch (lpToneGen->mState) {
396 case TONE_RESTARTING:
397 LOGV("Cbk restarting track\n");
398 if (lpToneGen->prepareWave()) {
399 lpToneGen->mState = TONE_STARTING;
400 } else {
401 lpToneGen->mState = TONE_INIT;
402 lpToneGen->mpAudioTrack->stop();
403 }
404 lSignal = true;
405 break;
406 case TONE_STOPPING:
407 lpToneGen->mState = TONE_INIT;
408 LOGV("Cbk Stopping track\n");
409 lSignal = true;
410 lpToneGen->mpAudioTrack->stop();
411 break;
412 case TONE_STARTING:
413 LOGV("Cbk starting track\n");
414 lpToneGen->mState = TONE_PLAYING;
415 lSignal = true;
416 break;
417 default:
418 break;
419 }
420
421 if (lSignal)
422 lpToneGen->mWaitCbkCond.signal();
423 lpToneGen->mLock.unlock();
424}
425
426
427////////////////////////////////////////////////////////////////////////////////
428//
429// Method: ToneGenerator::prepareWave()
430//
431// Description: Prepare wave generators and reset tone sequencer state machine.
432// mpNewToneDesc must have been initialized befoire calling this function.
433// Input:
434// none
435//
436// Output:
437// returned value: true if wave generators have been created, false otherwise
438//
439////////////////////////////////////////////////////////////////////////////////
440bool ToneGenerator::prepareWave() {
441 unsigned int lCnt = 0;
442 unsigned int lNumWaves;
443
444 if (!mpNewToneDesc) {
445 return false;
446 }
447 // Remove existing wave generators if any
448 clearWaveGens();
449
450 mpToneDesc = mpNewToneDesc;
451
452 // Get total number of sine waves: needed to adapt sine wave gain.
453 lNumWaves = numWaves();
454
455 // Instantiate as many wave generators as listed in descriptor
456 while (lCnt < lNumWaves) {
457 ToneGenerator::WaveGenerator *lpWaveGen =
458 new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
459 mpToneDesc->waveFreq[lCnt],
460 TONEGEN_GAIN/lNumWaves);
461 if (lpWaveGen == 0) {
462 goto prepareWave_exit;
463 }
464
465 mWaveGens.push(lpWaveGen);
466 LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
467 lCnt++;
468 }
469
470 // Initialize tone sequencer
471 mTotalSmp = 0;
472 mCurSegment = 0;
473 mCurCount = 0;
474 mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
475
476 return true;
477
478prepareWave_exit:
479
480 clearWaveGens();
481
482 return false;
483}
484
485
486////////////////////////////////////////////////////////////////////////////////
487//
488// Method: ToneGenerator::numWaves()
489//
490// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF).
491//
492// Input:
493// none
494//
495// Output:
496// returned value: nummber of sine waves
497//
498////////////////////////////////////////////////////////////////////////////////
499unsigned int ToneGenerator::numWaves() {
500 unsigned int lCnt = 0;
501
502 while (mpToneDesc->waveFreq[lCnt]) {
503 lCnt++;
504 }
505
506 return lCnt;
507}
508
509
510////////////////////////////////////////////////////////////////////////////////
511//
512// Method: ToneGenerator::clearWaveGens()
513//
514// Description: Removes all wave generators.
515//
516// Input:
517// none
518//
519// Output:
520// none
521//
522////////////////////////////////////////////////////////////////////////////////
523void ToneGenerator::clearWaveGens() {
524 LOGV("Clearing mWaveGens:");
525
526 while (!mWaveGens.isEmpty()) {
527 delete mWaveGens.top();
528 mWaveGens.pop();
529 }
530}
531
532
533////////////////////////////////////////////////////////////////////////////////
534// WaveGenerator::WaveGenerator class Implementation
535////////////////////////////////////////////////////////////////////////////////
536
537//---------------------------------- public methods ----------------------------
538
539////////////////////////////////////////////////////////////////////////////////
540//
541// Method: WaveGenerator::WaveGenerator()
542//
543// Description: Constructor.
544//
545// Input:
546// samplingRate: Output sampling rate in Hz
547// frequency: Frequency of the sine wave to generate in Hz
548// volume: volume (0.0 to 1.0)
549//
550// Output:
551// none
552//
553////////////////////////////////////////////////////////////////////////////////
554ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate,
555 unsigned short frequency, float volume) {
556 double d0;
557 double F_div_Fs; // frequency / samplingRate
558
559 F_div_Fs = frequency / (double)samplingRate;
560 d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
561 mS2_0 = (short)d0;
562 mS1 = 0;
563 mS2 = mS2_0;
564
565 mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
566 // take some margin for amplitude fluctuation
567 if (mAmplitude_Q15 > 32500)
568 mAmplitude_Q15 = 32500;
569
570 d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos()
571 if (d0 > 32767)
572 d0 = 32767;
573 mA1_Q14 = (short) d0;
574
575 LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
576 mA1_Q14, mS2_0, mAmplitude_Q15);
577}
578
579////////////////////////////////////////////////////////////////////////////////
580//
581// Method: WaveGenerator::~WaveGenerator()
582//
583// Description: Destructor.
584//
585// Input:
586// none
587//
588// Output:
589// none
590//
591////////////////////////////////////////////////////////////////////////////////
592ToneGenerator::WaveGenerator::~WaveGenerator() {
593}
594
595////////////////////////////////////////////////////////////////////////////////
596//
597// Method: WaveGenerator::getSamples()
598//
599// Description: Generates count samples of a sine wave and accumulates
600// result in outBuffer.
601//
602// Input:
603// outBuffer: Output buffer where to accumulate samples.
604// count: number of samples to produce.
605// command: special action requested (see enum gen_command).
606//
607// Output:
608// none
609//
610////////////////////////////////////////////////////////////////////////////////
611void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
612 unsigned int count, unsigned int command) {
613 long lS1, lS2;
614 long lA1, lAmplitude;
615 long Sample; // current sample
616
617 // init local
618 if (command == WAVEGEN_START) {
619 lS1 = (long)0;
620 lS2 = (long)mS2_0;
621 } else {
622 lS1 = (long)mS1;
623 lS2 = (long)mS2;
624 }
625 lA1 = (long)mA1_Q14;
626 lAmplitude = (long)mAmplitude_Q15;
627
628 if (command == WAVEGEN_STOP) {
629 lAmplitude <<= 16;
630 if (count == 0) {
631 return;
632 }
633 long dec = lAmplitude/count;
634 // loop generation
635 while (count--) {
636 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
637 // shift delay
638 lS2 = lS1;
639 lS1 = Sample;
640 Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
641 *(outBuffer++) += (short)Sample; // put result in buffer
642 lAmplitude -= dec;
643 }
644 } else {
645 // loop generation
646 while (count--) {
647 Sample = ((lA1 * lS1) >> S_Q14) - lS2;
648 // shift delay
649 lS2 = lS1;
650 lS1 = Sample;
651 Sample = (lAmplitude * Sample) >> S_Q15;
652 *(outBuffer++) += (short)Sample; // put result in buffer
653 }
654 }
655
656 // save status
657 mS1 = (short)lS1;
658 mS2 = (short)lS2;
659}
660
661} // end namespace android
662