2010-07-24 26 views

回答

25

這是我的代碼,用於從函數生成聲音。我假設你知道如何使用AudioQueue服務,設置AudioSession,並正確啓動和停止音頻輸出隊列。

這裏的設立和啓動輸出AudioQueue一個片段:

// Get the preferred sample rate (8,000 Hz on iPhone, 44,100 Hz on iPod touch) 
size = sizeof(sampleRate); 
err = AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareSampleRate, &size, &sampleRate); 
if (err != noErr) NSLog(@"AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate) error: %d", err); 
//NSLog (@"Current hardware sample rate: %1.0f", sampleRate); 

BOOL isHighSampleRate = (sampleRate > 16000); 
int bufferByteSize; 
AudioQueueBufferRef buffer; 

// Set up stream format fields 
AudioStreamBasicDescription streamFormat; 
streamFormat.mSampleRate = sampleRate; 
streamFormat.mFormatID = kAudioFormatLinearPCM; 
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; 
streamFormat.mBitsPerChannel = 16; 
streamFormat.mChannelsPerFrame = 1; 
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame; 
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame; 
streamFormat.mFramesPerPacket = 1; 
streamFormat.mReserved = 0; 

// New output queue ---- PLAYBACK ---- 
if (isPlaying == NO) { 
    err = AudioQueueNewOutput (&streamFormat, AudioEngineOutputBufferCallback, self, nil, nil, 0, &outputQueue); 
    if (err != noErr) NSLog(@"AudioQueueNewOutput() error: %d", err); 

    // Enqueue buffers 
    //outputFrequency = 0.0; 
    outputBuffersToRewrite = 3; 
    bufferByteSize = (sampleRate > 16000)? 2176 : 512; // 40.5 Hz : 31.25 Hz 
    for (i=0; i<3; i++) { 
     err = AudioQueueAllocateBuffer (outputQueue, bufferByteSize, &buffer); 
     if (err == noErr) { 
      [self generateTone: buffer]; 
      err = AudioQueueEnqueueBuffer (outputQueue, buffer, 0, nil); 
      if (err != noErr) NSLog(@"AudioQueueEnqueueBuffer() error: %d", err); 
     } else { 
      NSLog(@"AudioQueueAllocateBuffer() error: %d", err); 
      return; 
     } 
    } 

    // Start playback 
    isPlaying = YES; 
    err = AudioQueueStart(outputQueue, nil); 
    if (err != noErr) { NSLog(@"AudioQueueStart() error: %d", err); isPlaying= NO; return; } 
} else { 
    NSLog (@"Error: audio is already playing back."); 
} 

下面是產生音部分:

// AudioQueue output queue callback. 
void AudioEngineOutputBufferCallback (void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { 
    AudioEngine *engine = (AudioEngine*) inUserData; 
    [engine processOutputBuffer:inBuffer queue:inAQ]; 
} 

- (void) processOutputBuffer: (AudioQueueBufferRef) buffer queue:(AudioQueueRef) queue { 
    OSStatus err; 
    if (isPlaying == YES) { 
     [outputLock lock]; 
     if (outputBuffersToRewrite > 0) { 
      outputBuffersToRewrite--; 
      [self generateTone:buffer]; 
     } 
     err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); 
     if (err == 560030580) { // Queue is not active due to Music being started or other reasons 
      isPlaying = NO; 
     } else if (err != noErr) { 
      NSLog(@"AudioQueueEnqueueBuffer() error %d", err); 
     } 
     [outputLock unlock]; 
    } else { 
     err = AudioQueueStop (queue, NO); 
     if (err != noErr) NSLog(@"AudioQueueStop() error: %d", err); 
    } 
} 

-(void) generateTone: (AudioQueueBufferRef) buffer { 
    if (outputFrequency == 0.0) { 
     memset(buffer->mAudioData, 0, buffer->mAudioDataBytesCapacity); 
     buffer->mAudioDataByteSize = buffer->mAudioDataBytesCapacity; 
    } else { 
     // Make the buffer length a multiple of the wavelength for the output frequency. 
     int sampleCount = buffer->mAudioDataBytesCapacity/sizeof (SInt16); 
     double bufferLength = sampleCount; 
     double wavelength = sampleRate/outputFrequency; 
     double repetitions = floor (bufferLength/wavelength); 
     if (repetitions > 0.0) { 
      sampleCount = round (wavelength * repetitions); 
     } 

     double  x, y; 
     double  sd = 1.0/sampleRate; 
     double  amp = 0.9; 
     double  max16bit = SHRT_MAX; 
     int i; 
     SInt16 *p = buffer->mAudioData; 

     for (i = 0; i < sampleCount; i++) { 
      x = i * sd * outputFrequency; 
      switch (outputWaveform) { 
       case kSine: 
        y = sin (x * 2.0 * M_PI); 
        break; 
       case kTriangle: 
        x = fmod (x, 1.0); 
        if (x < 0.25) 
         y = x * 4.0; // up 0.0 to 1.0 
        else if (x < 0.75) 
         y = (1.0 - x) * 4.0 - 2.0; // down 1.0 to -1.0 
        else 
         y = (x - 1.0) * 4.0; // up -1.0 to 0.0 
        break; 
       case kSawtooth: 
        y = 0.8 - fmod (x, 1.0) * 1.8; 
        break; 
       case kSquare: 
        y = (fmod(x, 1.0) < 0.5)? 0.7: -0.7; 
        break; 
       default: y = 0; break; 
      } 
      p[i] = y * max16bit * amp; 
     } 

     buffer->mAudioDataByteSize = sampleCount * sizeof (SInt16); 
    } 
} 

事情需要提防的是,你的回調將被調用在非主線程上,所以您必須通過鎖,互斥鎖或其他技術來練習線程安全。

+0

你能分享你的代碼嗎? – 2017-06-05 11:20:56

7

高級別:使用AVAudioPlayer https://github.com/hollance/AVBufferPlayer

醫學水平:音頻序列trailsinthesand.com/exploring-iphone-audio-part-1/讓你去很好。注:我刪除了http,以便舊鏈接可以在那裏,但它確實指向了一個不好的網站,所以它顯然已經改變。

低電平:另外,您也可以下拉的水平,並與音頻單元做到這一點:http://cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html

+2

Synth中的音頻隊列:https://github.com/hollance/AudioBufferPlayer – 2011-04-11 13:01:32

+0

你的例子幫了我很多,再次感謝 – Amitg2k12 2011-05-14 14:53:56

9

這是使用相同的樣品的C#版本從@lucius

void SetupAudio() 
    { 
     AudioSession.Initialize(); 
     AudioSession.Category = AudioSessionCategory.MediaPlayback; 

     sampleRate = AudioSession.CurrentHardwareSampleRate; 
     var format = new AudioStreamBasicDescription() { 
      SampleRate = sampleRate, 
      Format = AudioFormatType.LinearPCM, 
      FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | AudioFormatFlags.LinearPCMIsPacked, 
      BitsPerChannel = 16, 
      ChannelsPerFrame = 1, 
      BytesPerFrame = 2, 
      BytesPerPacket = 2, 
      FramesPerPacket = 1, 
     }; 

     var queue = new OutputAudioQueue (format); 
     var bufferByteSize = (sampleRate > 16000)? 2176 : 512; // 40.5 Hz : 31.25 Hz 
     var buffers = new AudioQueueBuffer* [numBuffers]; 
     for (int i = 0; i < numBuffers; i++){ 
      queue.AllocateBuffer (bufferByteSize, out buffers [i]); 
      GenerateTone (buffers [i]); 
      queue.EnqueueBuffer (buffers [i], null); 
     } 
     queue.OutputCompleted += (object sender, OutputCompletedEventArgs e) => { 
      queue.EnqueueBuffer (e.UnsafeBuffer, null); 
     }; 

     queue.Start(); 
     return true; 
    } 

這是音調發生器:

void GenerateTone (AudioQueueBuffer *buffer) 
    { 
     // Make the buffer length a multiple of the wavelength for the output frequency. 
     uint sampleCount = buffer->AudioDataBytesCapacity/2; 
     double bufferLength = sampleCount; 
     double wavelength = sampleRate/outputFrequency; 
     double repetitions = Math.Floor (bufferLength/wavelength); 
     if (repetitions > 0) 
      sampleCount = (uint)Math.Round (wavelength * repetitions); 

     double  x, y; 
     double  sd = 1.0/sampleRate; 
     double  amp = 0.9; 
     double  max16bit = Int16.MaxValue; 
     int i; 
     short *p = (short *) buffer->AudioData; 

     for (i = 0; i < sampleCount; i++) { 
      x = i * sd * outputFrequency; 
      switch (outputWaveForm) { 
       case WaveForm.Sine: 
        y = Math.Sin (x * 2.0 * Math.PI); 
        break; 
       case WaveForm.Triangle: 
        x = x % 1.0; 
        if (x < 0.25) 
         y = x * 4.0; // up 0.0 to 1.0 
        else if (x < 0.75) 
         y = (1.0 - x) * 4.0 - 2.0; // down 1.0 to -1.0 
        else 
         y = (x - 1.0) * 4.0; // up -1.0 to 0.0 
        break; 
       case WaveForm.Sawtooth: 
        y = 0.8 - (x % 1.0) * 1.8; 
        break; 
       case WaveForm.Square: 
        y = ((x % 1.0) < 0.5)? 0.7: -0.7; 
        break; 
       default: y = 0; break; 
      } 
      p[i] = (short)(y * max16bit * amp); 
     } 
     buffer->AudioDataByteSize = sampleCount * 2; 
    } 
} 

您還希望這些定義:

enum WaveForm { 
     Sine, Triangle, Sawtooth, Square 
    } 
    WaveForm outputWaveForm; 
    const float outputFrequency = 220; 
相關問題