ToneGenerator.cpp revision 7b5eb023f8d87cca6d830ae6c11c6aadbe02aca8
1/* 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 92 LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume); 93 94 mState = TONE_IDLE; 95 96 if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) { 97 LOGE("Unable to marshal AudioFlinger"); 98 return; 99 } 100 if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) { 101 LOGE("Unable to marshal AudioFlinger"); 102 return; 103 } 104 mStreamType = streamType; 105 mVolume = volume; 106 mpAudioTrack = 0; 107 mpToneDesc = 0; 108 mpNewToneDesc = 0; 109 110 if (initAudioTrack()) { 111 LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000)); 112 } else { 113 LOGV("!!!ToneGenerator INIT FAILED!!!\n"); 114 } 115} 116 117 118 119 120//////////////////////////////////////////////////////////////////////////////// 121// 122// Method: ToneGenerator::~ToneGenerator() 123// 124// Description: Destructor. Stop sound playback and delete audio track if 125// needed and delete sine wave generators. 126// 127// Input: 128// none 129// 130// Output: 131// none 132// 133//////////////////////////////////////////////////////////////////////////////// 134ToneGenerator::~ToneGenerator() { 135 LOGV("ToneGenerator destructor\n"); 136 137 if (mpAudioTrack) { 138 stopTone(); 139 LOGV("Delete Track: %p\n", mpAudioTrack); 140 delete mpAudioTrack; 141 } 142} 143 144//////////////////////////////////////////////////////////////////////////////// 145// 146// Method: ToneGenerator::startTone() 147// 148// Description: Starts tone playback. 149// 150// Input: 151// none 152// 153// Output: 154// none 155// 156//////////////////////////////////////////////////////////////////////////////// 157bool ToneGenerator::startTone(int toneType) { 158 bool lResult = false; 159 160 if (toneType >= NUM_TONES) 161 return lResult; 162 163 if (mState == TONE_IDLE) { 164 LOGV("startTone: try to re-init AudioTrack"); 165 if (!initAudioTrack()) { 166 return lResult; 167 } 168 } 169 170 LOGV("startTone\n"); 171 172 mLock.lock(); 173 174 // Get descriptor for requested tone 175 mpNewToneDesc = &toneDescriptors[toneType]; 176 177 if (mState == TONE_INIT) { 178 if (prepareWave()) { 179 LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000)); 180 181 mState = TONE_STARTING; 182 mLock.unlock(); 183 mpAudioTrack->start(); 184 mLock.lock(); 185 if (mState == TONE_STARTING) { 186 if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) { 187 LOGE("--- timed out"); 188 mState = TONE_IDLE; 189 } 190 } 191 192 if (mState == TONE_PLAYING) 193 lResult = true; 194 } 195 } else { 196 LOGV("Delayed start\n"); 197 198 mState = TONE_RESTARTING; 199 if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) { 200 if (mState != TONE_INIT) { 201 lResult = true; 202 } 203 LOGV("cond received"); 204 } else { 205 LOGE("--- timed out"); 206 mState = TONE_IDLE; 207 } 208 } 209 mLock.unlock(); 210 211 LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000)); 212 213 return lResult; 214} 215 216//////////////////////////////////////////////////////////////////////////////// 217// 218// Method: ToneGenerator::stopTone() 219// 220// Description: Stops tone playback. 221// 222// Input: 223// none 224// 225// Output: 226// none 227// 228//////////////////////////////////////////////////////////////////////////////// 229void ToneGenerator::stopTone() { 230 LOGV("stopTone"); 231 232 mLock.lock(); 233 if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) { 234 mState = TONE_STOPPING; 235 LOGV("waiting cond"); 236 status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1)); 237 if (lStatus == NO_ERROR) { 238 LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000)); 239 } else { 240 LOGE("--- timed out"); 241 mState = TONE_IDLE; 242 mpAudioTrack->stop(); 243 } 244 } 245 246 clearWaveGens(); 247 248 mLock.unlock(); 249} 250 251//---------------------------------- private methods --------------------------- 252 253 254 255 256//////////////////////////////////////////////////////////////////////////////// 257// 258// Method: ToneGenerator::initAudioTrack() 259// 260// Description: Allocates and configures AudioTrack used for PCM output. 261// 262// Input: 263// none 264// 265// Output: 266// none 267// 268//////////////////////////////////////////////////////////////////////////////// 269bool ToneGenerator::initAudioTrack() { 270 271 if (mpAudioTrack) { 272 delete mpAudioTrack; 273 mpAudioTrack = 0; 274 } 275 276 // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers of 277 mpAudioTrack 278 = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS*mBufferSize, 0, audioCallback, this, mBufferSize); 279 280 if (mpAudioTrack == 0) { 281 LOGE("AudioTrack allocation failed"); 282 goto initAudioTrack_exit; 283 } 284 LOGV("Create Track: %p\n", mpAudioTrack); 285 286 if (mpAudioTrack->initCheck() != NO_ERROR) { 287 LOGE("AudioTrack->initCheck failed"); 288 goto initAudioTrack_exit; 289 } 290 291 mpAudioTrack->setVolume(mVolume, mVolume); 292 293 mState = TONE_INIT; 294 295 return true; 296 297initAudioTrack_exit: 298 299 // Cleanup 300 if (mpAudioTrack) { 301 LOGV("Delete Track I: %p\n", mpAudioTrack); 302 delete mpAudioTrack; 303 mpAudioTrack = 0; 304 } 305 306 return false; 307} 308 309 310//////////////////////////////////////////////////////////////////////////////// 311// 312// Method: ToneGenerator::audioCallback() 313// 314// Description: AudioTrack callback implementation. Generates a block of 315// PCM samples 316// and manages tone generator sequencer: tones pulses, tone duration... 317// 318// Input: 319// user reference (pointer to our ToneGenerator) 320// info audio buffer descriptor 321// 322// Output: 323// returned value: always true. 324// 325//////////////////////////////////////////////////////////////////////////////// 326void ToneGenerator::audioCallback(int event, void* user, void *info) { 327 328 if (event != AudioTrack::EVENT_MORE_DATA) return; 329 330 const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info); 331 ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user); 332 short *lpOut = buffer->i16; 333 unsigned int lReqSmp = buffer->size/sizeof(short); 334 unsigned int lGenSmp; 335 unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT; 336 bool lSignal = false; 337 338 if (buffer->size == 0) return; 339 340 lpToneGen->mLock.lock(); 341 342 // Clear output buffer: WaveGenerator accumulates into lpOut buffer 343 memset(lpOut, 0, buffer->size); 344 345 // Update pcm frame count and end time (current time at the end of this process) 346 lpToneGen->mTotalSmp += lReqSmp; 347 348 // Update tone gen state machine and select wave gen command 349 switch (lpToneGen->mState) { 350 case TONE_PLAYING: 351 lWaveCmd = WaveGenerator::WAVEGEN_CONT; 352 break; 353 case TONE_STARTING: 354 LOGV("Starting Cbk"); 355 356 lWaveCmd = WaveGenerator::WAVEGEN_START; 357 break; 358 case TONE_STOPPING: 359 case TONE_RESTARTING: 360 LOGV("Stop/restart Cbk"); 361 362 lWaveCmd = WaveGenerator::WAVEGEN_STOP; 363 lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below 364 break; 365 default: 366 LOGV("Extra Cbk"); 367 goto audioCallback_Exit; 368 } 369 370 // Exit if tone sequence is over 371 if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) { 372 if (lpToneGen->mState == TONE_PLAYING) { 373 lpToneGen->mState = TONE_STOPPING; 374 } 375 goto audioCallback_Exit; 376 } 377 378 if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) { 379 // Time to go to next sequence segment 380 381 LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000)); 382 383 lGenSmp = lReqSmp; 384 385 if (lpToneGen->mCurSegment & 0x0001) { 386 // If odd segment, OFF -> ON transition : reset wave generator 387 lWaveCmd = WaveGenerator::WAVEGEN_START; 388 389 LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); 390 } else { 391 // If even segment, ON -> OFF transition : ramp volume down 392 lWaveCmd = WaveGenerator::WAVEGEN_STOP; 393 394 LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); 395 } 396 397 // Pre increment segment index and handle loop if last segment reached 398 if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) { 399 LOGV("Last Seg: %d\n", lpToneGen->mCurSegment); 400 401 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise 402 if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) { 403 LOGV("Repeating Count: %d\n", lpToneGen->mCurCount); 404 405 lpToneGen->mCurSegment = 0; 406 407 LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, 408 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); 409 410 } else { 411 LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000)); 412 413 // Cancel OFF->ON transition in case previous segment tone state was OFF 414 if (!(lpToneGen->mCurSegment & 0x0001)) { 415 lGenSmp = 0; 416 } 417 } 418 } else { 419 LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, 420 (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); 421 } 422 423 // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more 424 lpToneGen->mNextSegSmp 425 += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000; 426 427 } else { 428 // Inside a segment keep tone ON or OFF 429 if (lpToneGen->mCurSegment & 0x0001) { 430 lGenSmp = 0; // If odd segment, tone is currently OFF 431 } else { 432 lGenSmp = lReqSmp; // If event segment, tone is currently ON 433 } 434 } 435 436 if (lGenSmp) { 437 // If samples must be generated, call all active wave generators and acumulate waves in lpOut 438 unsigned int lWaveIdx; 439 440 for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) { 441 WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx]; 442 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd); 443 } 444 } 445 446audioCallback_Exit: 447 448 switch (lpToneGen->mState) { 449 case TONE_RESTARTING: 450 LOGV("Cbk restarting track\n"); 451 if (lpToneGen->prepareWave()) { 452 lpToneGen->mState = TONE_STARTING; 453 } else { 454 lpToneGen->mState = TONE_INIT; 455 lpToneGen->mpAudioTrack->stop(); 456 } 457 lSignal = true; 458 break; 459 case TONE_STOPPING: 460 lpToneGen->mState = TONE_INIT; 461 LOGV("Cbk Stopping track\n"); 462 lSignal = true; 463 lpToneGen->mpAudioTrack->stop(); 464 break; 465 case TONE_STARTING: 466 LOGV("Cbk starting track\n"); 467 lpToneGen->mState = TONE_PLAYING; 468 lSignal = true; 469 break; 470 default: 471 break; 472 } 473 474 if (lSignal) 475 lpToneGen->mWaitCbkCond.signal(); 476 lpToneGen->mLock.unlock(); 477} 478 479 480//////////////////////////////////////////////////////////////////////////////// 481// 482// Method: ToneGenerator::prepareWave() 483// 484// Description: Prepare wave generators and reset tone sequencer state machine. 485// mpNewToneDesc must have been initialized befoire calling this function. 486// Input: 487// none 488// 489// Output: 490// returned value: true if wave generators have been created, false otherwise 491// 492//////////////////////////////////////////////////////////////////////////////// 493bool ToneGenerator::prepareWave() { 494 unsigned int lCnt = 0; 495 unsigned int lNumWaves; 496 497 if (!mpNewToneDesc) { 498 return false; 499 } 500 // Remove existing wave generators if any 501 clearWaveGens(); 502 503 mpToneDesc = mpNewToneDesc; 504 505 // Get total number of sine waves: needed to adapt sine wave gain. 506 lNumWaves = numWaves(); 507 508 // Instantiate as many wave generators as listed in descriptor 509 while (lCnt < lNumWaves) { 510 ToneGenerator::WaveGenerator *lpWaveGen = 511 new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate, 512 mpToneDesc->waveFreq[lCnt], 513 TONEGEN_GAIN/lNumWaves); 514 if (lpWaveGen == 0) { 515 goto prepareWave_exit; 516 } 517 518 mWaveGens.push(lpWaveGen); 519 LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]); 520 lCnt++; 521 } 522 523 // Initialize tone sequencer 524 mTotalSmp = 0; 525 mCurSegment = 0; 526 mCurCount = 0; 527 mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000; 528 529 return true; 530 531prepareWave_exit: 532 533 clearWaveGens(); 534 535 return false; 536} 537 538 539//////////////////////////////////////////////////////////////////////////////// 540// 541// Method: ToneGenerator::numWaves() 542// 543// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF). 544// 545// Input: 546// none 547// 548// Output: 549// returned value: nummber of sine waves 550// 551//////////////////////////////////////////////////////////////////////////////// 552unsigned int ToneGenerator::numWaves() { 553 unsigned int lCnt = 0; 554 555 while (mpToneDesc->waveFreq[lCnt]) { 556 lCnt++; 557 } 558 559 return lCnt; 560} 561 562 563//////////////////////////////////////////////////////////////////////////////// 564// 565// Method: ToneGenerator::clearWaveGens() 566// 567// Description: Removes all wave generators. 568// 569// Input: 570// none 571// 572// Output: 573// none 574// 575//////////////////////////////////////////////////////////////////////////////// 576void ToneGenerator::clearWaveGens() { 577 LOGV("Clearing mWaveGens:"); 578 579 while (!mWaveGens.isEmpty()) { 580 delete mWaveGens.top(); 581 mWaveGens.pop(); 582 } 583} 584 585 586//////////////////////////////////////////////////////////////////////////////// 587// WaveGenerator::WaveGenerator class Implementation 588//////////////////////////////////////////////////////////////////////////////// 589 590//---------------------------------- public methods ---------------------------- 591 592//////////////////////////////////////////////////////////////////////////////// 593// 594// Method: WaveGenerator::WaveGenerator() 595// 596// Description: Constructor. 597// 598// Input: 599// samplingRate: Output sampling rate in Hz 600// frequency: Frequency of the sine wave to generate in Hz 601// volume: volume (0.0 to 1.0) 602// 603// Output: 604// none 605// 606//////////////////////////////////////////////////////////////////////////////// 607ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate, 608 unsigned short frequency, float volume) { 609 double d0; 610 double F_div_Fs; // frequency / samplingRate 611 612 F_div_Fs = frequency / (double)samplingRate; 613 d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs); 614 mS2_0 = (short)d0; 615 mS1 = 0; 616 mS2 = mS2_0; 617 618 mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP); 619 // take some margin for amplitude fluctuation 620 if (mAmplitude_Q15 > 32500) 621 mAmplitude_Q15 = 32500; 622 623 d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos() 624 if (d0 > 32767) 625 d0 = 32767; 626 mA1_Q14 = (short) d0; 627 628 LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n", 629 mA1_Q14, mS2_0, mAmplitude_Q15); 630} 631 632//////////////////////////////////////////////////////////////////////////////// 633// 634// Method: WaveGenerator::~WaveGenerator() 635// 636// Description: Destructor. 637// 638// Input: 639// none 640// 641// Output: 642// none 643// 644//////////////////////////////////////////////////////////////////////////////// 645ToneGenerator::WaveGenerator::~WaveGenerator() { 646} 647 648//////////////////////////////////////////////////////////////////////////////// 649// 650// Method: WaveGenerator::getSamples() 651// 652// Description: Generates count samples of a sine wave and accumulates 653// result in outBuffer. 654// 655// Input: 656// outBuffer: Output buffer where to accumulate samples. 657// count: number of samples to produce. 658// command: special action requested (see enum gen_command). 659// 660// Output: 661// none 662// 663//////////////////////////////////////////////////////////////////////////////// 664void ToneGenerator::WaveGenerator::getSamples(short *outBuffer, 665 unsigned int count, unsigned int command) { 666 long lS1, lS2; 667 long lA1, lAmplitude; 668 long Sample; // current sample 669 670 // init local 671 if (command == WAVEGEN_START) { 672 lS1 = (long)0; 673 lS2 = (long)mS2_0; 674 } else { 675 lS1 = (long)mS1; 676 lS2 = (long)mS2; 677 } 678 lA1 = (long)mA1_Q14; 679 lAmplitude = (long)mAmplitude_Q15; 680 681 if (command == WAVEGEN_STOP) { 682 lAmplitude <<= 16; 683 if (count == 0) { 684 return; 685 } 686 long dec = lAmplitude/count; 687 // loop generation 688 while (count--) { 689 Sample = ((lA1 * lS1) >> S_Q14) - lS2; 690 // shift delay 691 lS2 = lS1; 692 lS1 = Sample; 693 Sample = ((lAmplitude>>16) * Sample) >> S_Q15; 694 *(outBuffer++) += (short)Sample; // put result in buffer 695 lAmplitude -= dec; 696 } 697 } else { 698 // loop generation 699 while (count--) { 700 Sample = ((lA1 * lS1) >> S_Q14) - lS2; 701 // shift delay 702 lS2 = lS1; 703 lS1 = Sample; 704 Sample = (lAmplitude * Sample) >> S_Q15; 705 *(outBuffer++) += (short)Sample; // put result in buffer 706 } 707 } 708 709 // save status 710 mS1 = (short)lS1; 711 mS2 = (short)lS2; 712} 713 714} // end namespace android 715 716