2009-09-01 9 views
18

iPhoneで合成音を再生したいのですが?あらかじめ録音されたサウンドを使用し、SystemSoundIDを使って既存のバイナリを再生する代わりに、それを合成したいと思います。部分的には、一回限りのサウンドサンプルではなく、サウンドを連続して再生できるようにするためです(たとえば、ユーザーの指が画面上にあるときなど)。iPhone/MacでCoreAudioを使ってサウンドを合成する方法

ミドルA + 1(A4)(440Hz)を合成したい場合、sin()を使って正弦波を計算できます。私が知らないのは、これらのビットをCoreAudioが再生できるパケットに整理する方法です。ネット上に存在するチュートリアルのほとんどは、単に既存のバイナリを再生することに関係しています。

440Hzで単純な合成正弦波を手伝ってもらえますか?

答えて

13

おそらくAudioQueueをセットアップするために何をしたいのですか?コールバックで合成されたオーディオデータをバッファに書き込むことができます。あなたのような新しいスレッドで実行するようにセットアップAudeioQueueます:AudioQueueは、より多くのデータが必要なときにいつでもコールバックメソッドAudioQueueCallbackは、

#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(); 
    } 

呼び出されます。

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); 
} 
+0

これは正しくありません。割り当てループでAudioQueueCallbackを呼び出すべきではありません。私は説明が正しく設定されているとは思わない。 さらに、この奇妙な方法の代わりにAudioQueueStart(audioQueue、nil)を呼び出す必要があります。代わりにAudioUnit Frameworkを見てください。 – thefaj

+0

@thefaj:私はあなたが間違っている人だと信じています。この例は、私のアプリケーションのSC68 Player(http://itunes.apple.com/se/app/sc68-player/id295290413?mt=8)から取られています。ここでは、もともとAppleのiPhoneアプリケーションの例からオーディオ再生のコードを取得していますSpeakHere(http://developer.apple.com/iphone/library/samplecode/SpeakHere/)では、AQPlayer.mmファイルを見てください。 SC68プレーヤーの完全なソースコードが利用可能です(http://www.peylow.se/sc68player.html)。 – PeyloW

+0

あなたの例には、AudioQueueCallbackの呼び出し方法であるAudioQueueStart()がありません。 – thefaj

0

多くのオーディオテクノロジでは、サウンドファイルの代わりにデータを渡すことができます。 AVAudioPlayerは、例えば、持っている:

-initWithData:error: 
Initializes and returns an audio player for playing a designated memory buffer. 

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

はしかし、私はあなたがデータPTRに渡すだろうかわからない、音を起動し、他のデータPTRSに渡し、またはこれを繰り返すことで、ループそれを維持します、

4

アップルリストが応答しないように見えるので、http://lists.apple.com/archives/coreaudio-api/2008/Dec/msg00173.htmlにダヴィデVostiのリンクはもはや、動作します:ようなもので実装します。完全性のためのGoogleのキャッシュは次のとおりです。

// 
// 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 
+0

私はそれをDavideの質問にコメントとして追加しましたが、コメントには600文字の制限があります。 – AlBlue

関連する問題