首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在iPhone/Mac上用CoreAudio合成声音

如何在iPhone/Mac上用CoreAudio合成声音
EN

Stack Overflow用户
提问于 2009-09-01 08:00:57
回答 3查看 9.5K关注 0票数 17

我想用iPhone播放合成的声音。与其使用预先录制的声音并使用SystemSoundID播放现有的二进制文件,我想要合成它。在某种程度上,这是因为我希望能够连续播放声音(例如,当用户的手指在屏幕上时),而不是一次性的声音样本。

如果我想合成一个中间A+1 (A4) (440 If ),我可以使用sin()计算一个正弦波;我不知道的是如何将这些比特排列到一个包中,然后CoreAudio可以播放。网上存在的大多数教程都是关于简单地播放现有的二进制文件。

有人能帮我合成一个440赫兹的正弦波吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-09-02 14:09:43

你想做什么,可能是为了设置一个AudioQueue。它允许您在回调中使用合成的音频数据填充缓冲区。可以将AudeioQueue设置为在新线程中运行,如下所示:

代码语言:javascript
复制
#define BUFFER_SIZE 16384
#define BUFFER_COUNT 3
static AudioQueueRef audioQueue;
void SetupAudioQueue() {
    OSStatus err = noErr;
    // Setup the audio device.
    AudioStreamBasicDescription deviceFormat;
    deviceFormat.mSampleRate = 44100;
    deviceFormat.mFormatID = kAudioFormatLinearPCM;
    deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
    deviceFormat.mBytesPerPacket = 4;
    deviceFormat.mFramesPerPacket = 1;
    deviceFormat.mBytesPerFrame = 4;
    deviceFormat.mChannelsPerFrame = 2;
    deviceFormat.mBitsPerChannel = 16;
    deviceFormat.mReserved = 0;
    // Create a new output AudioQueue for the device.
    err = AudioQueueNewOutput(&deviceFormat, AudioQueueCallback, NULL,
                              CFRunLoopGetCurrent(), kCFRunLoopCommonModes,
                              0, &audioQueue);
    // Allocate buffers for the AudioQueue, and pre-fill them.
    for (int i = 0; i < BUFFER_COUNT; ++i) {
        AudioQueueBufferRef mBuffer;
        err = AudioQueueAllocateBuffer(audioQueue, BUFFER_SIZE, mBuffer);
        if (err != noErr) break;
        AudioQueueCallback(NULL, audioQueue, mBuffer);
    }
    if (err == noErr) err = AudioQueueStart(audioQueue, NULL);
    if (err == noErr) CFRunLoopRun();
  }

当AudioQueue需要更多数据时,您的回调方法AudioQueueCallback将被调用。使用类似以下内容来实现:

代码语言:javascript
复制
void AudioQueueCallback(void* inUserData, AudioQueueRef inAQ,
                        AudioQueueBufferRef inBuffer) {
    void* pBuffer = inBuffer->mAudioData;
    UInt32 bytes = inBuffer->mAudioDataBytesCapacity;
    // Write max <bytes> bytes of audio to <pBuffer>
    outBuffer->mAudioDataByteSize = actualNumberOfBytesWritten
    err = AudioQueueEnqueueBuffer(audioQueue, inBuffer, 0, NULL);
}
票数 13
EN

Stack Overflow用户

发布于 2011-11-01 16:59:03

戴维德·沃斯蒂与http://lists.apple.com/archives/coreaudio-api/2008/Dec/msg00173.html的链接不再有效,因为苹果名单似乎没有反应。以下是Google的缓存以保证完整性。

代码语言:javascript
复制
//
//  AudioUnitTestAppDelegate.m
//  AudioUnitTest
//
//  Created by Marc Vaillant on 11/25/08.
//  Copyright __MyCompanyName__ 2008. All rights reserved.
//

#import "AudioUnitTestAppDelegate.h"
#include <AudioUnit/AudioUnit.h>
//#include "MachTimer.hpp"
#include <vector>
#include <iostream>

using namespace std;

#define kOutputBus 0
#define kInputBus 1
#define SAMPLE_RATE 44100

vector<int> _pcm;
int _index;

@implementation AudioUnitTestAppDelegate

@synthesize window;

void generateTone(
                vector<int>& pcm, 
                int freq, 
                double lengthMS, 
                int sampleRate, 
                double riseTimeMS, 
                double gain)
{
  int numSamples = ((double) sampleRate) * lengthMS / 1000.;
  int riseTimeSamples = ((double) sampleRate) * riseTimeMS / 1000.;

  if(gain > 1.)
    gain = 1.;
  if(gain < 0.)
    gain = 0.;

  pcm.resize(numSamples);

  for(int i = 0; i < numSamples; ++i)
  {
    double value = sin(2. * M_PI * freq * i / sampleRate);
    if(i < riseTimeSamples)
      value *= sin(i * M_PI / (2.0 * riseTimeSamples));
    if(i > numSamples - riseTimeSamples - 1)
      value *= sin(2. * M_PI * (i - (numSamples - riseTimeSamples) + riseTimeSamples)/ (4. * riseTimeSamples));

    pcm[i] = (int) (value * 32500.0 * gain);
    pcm[i] += (pcm[i]<<16);
  }

}

static OSStatus playbackCallback(void *inRefCon, 
                                  AudioUnitRenderActionFlags *ioActionFlags, 
                                  const AudioTimeStamp *inTimeStamp, 
                                  UInt32 inBusNumber, 
                                  UInt32 inNumberFrames, 
                                  AudioBufferList *ioData) 
{    
    cout<<"index = "<<_index<<endl;
    cout<<"numBuffers = "<<ioData->mNumberBuffers<<endl;

    int totalNumberOfSamples = _pcm.size();
    for(UInt32 i = 0; i < ioData->mNumberBuffers; ++i)
    {
      int samplesLeft = totalNumberOfSamples - _index;
      int numSamples = ioData->mBuffers[i].mDataByteSize / 4;
      if(samplesLeft > 0)
      {
        if(samplesLeft < numSamples)
        {
          memcpy(ioData->mBuffers[i].mData, &_pcm[_index], samplesLeft * 4);
          _index += samplesLeft;
          memset((char*) ioData->mBuffers[i].mData + samplesLeft * 4, 0, (numSamples - samplesLeft) * 4) ;
        }
        else
        {
          memcpy(ioData->mBuffers[i].mData, &_pcm[_index], numSamples * 4) ;
          _index += numSamples;
        }
      }
      else
        memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
    }

    return noErr;
}

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{    
  //generate pcm tone  freq = 800, duration = 1s, rise/fall time = 5ms

  generateTone(_pcm, 800, 1000, SAMPLE_RATE, 5, 0.8);
  _index = 0;

  OSStatus status;
  AudioComponentInstance audioUnit;

  // Describe audio component
  AudioComponentDescription desc;
  desc.componentType = kAudioUnitType_Output;
  desc.componentSubType = kAudioUnitSubType_RemoteIO;
  desc.componentFlags = 0;
  desc.componentFlagsMask = 0;
  desc.componentManufacturer = kAudioUnitManufacturer_Apple;

  // Get component
  AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

  // Get audio units
  status = AudioComponentInstanceNew(inputComponent, &audioUnit);
  //checkStatus(status);

  UInt32 flag = 1;
  // Enable IO for playback
  status = AudioUnitSetProperty(audioUnit, 
                  kAudioOutputUnitProperty_EnableIO, 
                  kAudioUnitScope_Output, 
                  kOutputBus,
                  &flag, 
                  sizeof(flag));
  //checkStatus(status);

  // Describe format

  AudioStreamBasicDescription audioFormat;
  audioFormat.mSampleRate = SAMPLE_RATE;
  audioFormat.mFormatID = kAudioFormatLinearPCM;
  audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
  audioFormat.mFramesPerPacket = 1;
  audioFormat.mChannelsPerFrame = 2;
  audioFormat.mBitsPerChannel = 16;
  audioFormat.mBytesPerPacket = 4;
  audioFormat.mBytesPerFrame = 4;

  // Apply format

  status = AudioUnitSetProperty(audioUnit, 
                  kAudioUnitProperty_StreamFormat, 
                  kAudioUnitScope_Input, 
                  kOutputBus, 
                  &audioFormat, 
                  sizeof(audioFormat));
//  checkStatus(status);

  // Set output callback
  AURenderCallbackStruct callbackStruct;
  callbackStruct.inputProc = playbackCallback;
  callbackStruct.inputProcRefCon = self;
  status = AudioUnitSetProperty(audioUnit, 
                  kAudioUnitProperty_SetRenderCallback, 
                  kAudioUnitScope_Global, 
                  kOutputBus,
                  &callbackStruct, 
                  sizeof(callbackStruct));

  // Initialize
  status = AudioUnitInitialize(audioUnit);

  // Start playing

  status = AudioOutputUnitStart(audioUnit);

  [window makeKeyAndVisible];
}


- (void)dealloc {
    [window release];
    [super dealloc];
}


@end
票数 3
EN

Stack Overflow用户

发布于 2009-09-01 08:56:21

许多音频技术允许传入数据而不是声音文件。例如,AVAudioPlayer具有:

代码语言:javascript
复制
-initWithData:error:
Initializes and returns an audio player for playing a designated memory buffer.

- (id)initWithData:(NSData *)data error:(NSError **)outError

但是,我不确定如何传递数据ptr,启动声音,然后通过传递其他数据ptr或重复相同的数据来保持其循环。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1361148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档