在iOS 6中使用AudioFileServices粒子合成 [英] Granular Synthesis in iOS 6 using AudioFileServices

查看:239
本文介绍了在iOS 6中使用AudioFileServices粒子合成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有关于说我工作的一个声音合成应用程序的问题。我试图在音频文件读取,创建随机'杂粮'使用颗粒合成技术的,地点他们到一个输出缓冲,然后才能发挥这一回使用OpenAL的用户。出于测试目的,我只是写输出缓冲到一个文件,我可以再听听回。

I have a question regarding a sound synthesis app that I'm working on. I am trying to read in an audio file, create randomized 'grains' using granular synthesis techniques, place them into an output buffer and then be able to play that back to the user using OpenAL. For testing purposes, I am simply writing the output buffer to a file that I can then listen back to.

看我的成绩,我在正确的轨道上,但我得到一些锯齿问题,并播放声音,只是似乎不太对劲。通常有在输出文件以及调整音量中间的相当响亮的流行是非常响亮的时间。

Judging by my results, I am on the right track but am getting some aliasing issues and playback sounds that just don't seem quite right. There is usually a rather loud pop in the middle of the output file and volume levels are VERY loud at times.

下面是我已经得到我需要的结果的步骤,但我是一个有点困惑的几件事情,即格式,我指定我AudioStreamBasicDescription。

Here are the steps that I have taken to get the results I need, but I'm a little bit confused about a couple of things, namely formats that I am specifying for my AudioStreamBasicDescription.


  1. 读取来自我的mainBundle,这是在.AIFF格式单文件的音频文件:

  1. Read in an audio file from my mainBundle, which is a mono file in .aiff format:

ExtAudioFileRef extAudioFile;
CheckError(ExtAudioFileOpenURL(loopFileURL,
                           &extAudioFile),
       "couldn't open extaudiofile for reading");
memset(&player->dataFormat, 0, sizeof(player->dataFormat));

player->dataFormat.mFormatID = kAudioFormatLinearPCM;
player->dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
player->dataFormat.mSampleRate = S_RATE;
player->dataFormat.mChannelsPerFrame = 1;
player->dataFormat.mFramesPerPacket = 1;
player->dataFormat.mBitsPerChannel = 16;
player->dataFormat.mBytesPerFrame = 2;
player->dataFormat.mBytesPerPacket = 2;

// tell extaudiofile about our format
CheckError(ExtAudioFileSetProperty(extAudioFile,
                               kExtAudioFileProperty_ClientDataFormat,
                               sizeof(AudioStreamBasicDescription),
                               &player->dataFormat),
       "couldnt set client format on extaudiofile");

SInt64 fileLengthFrames;
UInt32 propSize = sizeof(fileLengthFrames);
ExtAudioFileGetProperty(extAudioFile,
                    kExtAudioFileProperty_FileLengthFrames,
                    &propSize,
                    &fileLengthFrames);

player->bufferSizeBytes = fileLengthFrames * player->dataFormat.mBytesPerFrame;


  • 接下来我宣布我的AudioBufferList并设置一些更多的属性。

  • Next I declare my AudioBufferList and set some more properties

    AudioBufferList *buffers;
    UInt32 ablSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1);
    buffers = (AudioBufferList *)malloc(ablSize);
    
    player->sampleBuffer = (SInt16 *)malloc(sizeof(SInt16) * player->bufferSizeBytes);
    
    buffers->mNumberBuffers = 1;
    buffers->mBuffers[0].mNumberChannels = 1;
    buffers->mBuffers[0].mDataByteSize = player->bufferSizeBytes;
    buffers->mBuffers[0].mData = player->sampleBuffer;
    


  • 我的理解是,.mData将是什么在formatFlags指定(在这种情况下,类型SInt16)。既然是类型(无效的 * 的),我想将它转换为浮动这是音频处理明显的数据。之前,我成立了一个for循环刚刚通过缓冲迭代和每个样本转换为浮动*。这似乎不必要所以现在我在.mData缓冲区传递到我创建了一个函数,然后granularizes音频:

  • My understanding is that .mData will be whatever was specified in the formatFlags (in this case, type SInt16). Since it is of type (void *), I want to convert this to float data which is obvious for audio manipulation. Before I set up a for loop which just iterated through the buffer and cast each sample to a float*. This seemed unnecessary so now I pass in my .mData buffer to a function I created which then granularizes the audio:

        float *theOutBuffer = [self granularizeWithData:(float *)buffers->mBuffers[0].mData with:framesRead];
    


  • 在此功能,我分配动态缓冲区一些,创建随机大小粒,将它们放置在我出缓冲器采用汉明窗窗后,他们并返回缓冲器(是浮动的数据)。一切都很酷到这一点。

  • In this function, I dynamically allocate some buffers, create random size grains, place them in my out buffer after windowing them using a hamming window and return that buffer (which is float data). Everything is cool up to this point.

    接下来,我建立了我的所有输出文件ASBD和这样的:

    Next I set up all my output file ASBD and such:

    AudioStreamBasicDescription outputFileFormat;
    
    bzero(audioFormatPtr, sizeof(AudioStreamBasicDescription));
    
    outputFileFormat->mFormatID = kAudioFormatLinearPCM;
    outputFileFormat->mSampleRate = 44100.0;
    outputFileFormat->mChannelsPerFrame = numChannels;
    outputFileFormat->mBytesPerPacket = 2 * numChannels;
    outputFileFormat->mFramesPerPacket = 1;
    outputFileFormat->mBytesPerFrame = 2 * numChannels;
    outputFileFormat->mBitsPerChannel = 16;
    outputFileFormat->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
    
    UInt32 flags = kAudioFileFlags_EraseFile;
    ExtAudioFileRef outputAudioFileRef = NULL;
    NSString *tmpDir = NSTemporaryDirectory();
    NSString *outFilename = @"Decomp.caf";
    NSString *outPath = [tmpDir stringByAppendingPathComponent:outFilename];
    NSURL *outURL = [NSURL fileURLWithPath:outPath];
    
    
    AudioBufferList *outBuff;
    UInt32 abSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1);
    outBuff = (AudioBufferList *)malloc(abSize);
    
    outBuff->mNumberBuffers = 1;
    outBuff->mBuffers[0].mNumberChannels = 1;
    outBuff->mBuffers[0].mDataByteSize = abSize;
    outBuff->mBuffers[0].mData = theOutBuffer;
    
    CheckError(ExtAudioFileCreateWithURL((__bridge CFURLRef)outURL,
                                     kAudioFileCAFType,
                                     &outputFileFormat,
                                     NULL,
                                     flags,
                                     &outputAudioFileRef),
           "ErrorCreatingURL_For_EXTAUDIOFILE");
    
    CheckError(ExtAudioFileSetProperty(outputAudioFileRef,
                                   kExtAudioFileProperty_ClientDataFormat,
                                   sizeof(outputFileFormat),
                                   &outputFileFormat),
           "ErrorSettingProperty_For_EXTAUDIOFILE");
    
    CheckError(ExtAudioFileWrite(outputAudioFileRef,
                             framesRead,
                             outBuff),
           "ErrorWritingFile");
    


  • 该文件被正确地写入,在CAF格式。我的问题是这样的:我在正确处理.mData缓冲区,我铸样品浮点数据,操纵(造粒)的各种窗口大小,然后将它写入到使用ExtAudioFileWrite一个文件(CAF格式)?有没有更优雅的方式来做到这一点,如宣布我ASBD formatFlag为kAudioFlagIsFloat?我的输出文件的CAF中有一些点击,当我在Logic打开它,它看起来像有很多别名。这是有道理的,如果我想将其发送浮动数据,但有某种转换发生的这我不知道。

    The file is written correctly, in CAF format. My question is this: am I handling the .mData buffer correctly in that I am casting the samples to float data, manipulating (granulating) various window sizes and then writing it to a file using ExtAudioFileWrite (in CAF format)? Is there a more elegant way to do this such as declaring my ASBD formatFlag as kAudioFlagIsFloat? My output CAF file has some clicks in it and when I open it in Logic, it looks like there is a lot of aliasing. This makes sense if I am trying to send it float data but there is some kind of conversion happening which I am unaware of.

    在此先感谢对此事的任何建议!我一直pretty的热心读者都很多材料的来源网上,包括C​​ore声读物,各种博客,教程等我的应用程序的最终目标是发挥实时音频颗粒化与用户耳机所以只是被用于目前测试写入文件的事情。谢谢!

    Thanks in advance for any advice on the matter! I have been an avid reader of pretty much all the source material online, including the Core Audio Book, various blogs, tutorials, etc. The ultimate goal of my app is to play the granularized audio in real time to a user with headphones so the writing to file thing is just being used for testing at the moment. Thanks!

    推荐答案

    你说什么第3步,令我你是间preting短裤数组作为float数组?如果是这样的话,我们发现你麻烦的原因。您可以指定短值逐个放入float数组?这应该修复它。

    What you say about step 3 suggests to me you are interpreting an array of shorts as an array of floats? If that is so, we found the reason for your trouble. Can you assign the short values one by one into an array of floats? That should fix it.

    看起来 MDATA 无效* 指向短裤的数组。铸造这个指针浮法* 不改变基础数据为浮动,但您的音频处理功能将把它们好像他们。然而,浮动值存储在完全不同的方式,让你在这个函数做数学题将要操作有无关,与你的真实的输入信号非常不同的值。通过实验研究这个,请尝试以下操作:

    It looks like mData is a void * pointing to an array of shorts. Casting this pointer to a float * doesn't change the underlying data into float but your audio processing function will treat them as if they were. However, float and short values are stored in totally different ways, so the math you do in that function will operate on very different values that have nothing to do with your true input signal. To investigate this experimentally, try the following:

    short data[4] = {-27158, 16825, 23024, 15};
    void *pData = data;
    

    无效指针并不表示它指向的是什么样的数据,因此错误,可以错误地假定它指向浮动值。请注意, 2字节宽,但浮动为4字节宽。这是你的code没有与访问冲突崩溃巧合。 PTED为国米$ P $浮动上面的阵列只有两个值足够长的时间。就让我们看一看在第一个值:

    The void pointer doesn't indicate what kind of data it points to, so erroneously, one can falsely assume it points to float values. Note that a short is 2 byte wide, but a float is 4 byte wide. It is a coincidence that your code did not crash with an access violation. Interpreted as float the array above is only long enough for two values. Let's just look at the first value:

    float *pfData = (float *)pData;
    printf("%d == %f\n", data[0], pfData[0]);
    

    这样做的输出将是 -27158 == 23.198200 ,说明如何而不是预期的 -27158.0f 你获得约 23.2f 。两个有问题的事情发生了。首先,的sizeof(浮动)不是的sizeof(短)。第二,一和零一个浮点数存储比的整数非常不同。请参见 http://en.wikipedia.org/wiki/Single_$p$pcision_floating- point_format

    The output of this will be -27158 == 23.198200 illustrating how instead of the expected -27158.0f you obtain roughly 23.2f. Two problematic things happened. First, sizeof(float) is not sizeof(short). Second, the "ones and zeros" of a floating point number are stored very differently than an integer. See http://en.wikipedia.org/wiki/Single_precision_floating-point_format.

    如何解决这个问题呢?至少有两种简单的解决办法。首先,你可以每个元素你给它之前转换数组到您的音频处理器:

    How to solve the problem? There are at least two simple solutions. First, you could convert each element of the array before you feed it into your audio processor:

    int k;
    float *pfBuf = (float *)malloc(n_data * sizeof(float));
    short *psiBuf = (short *)buffers->mBuffers[0].mData[k];
    for (k = 0; k < n_data; k ++)
    {
        pfBuf[k] = psiBuf[k];
    }
    [self granularizeWithData:pfBuf with:framesRead];
    for (k = 0; k < n_data; k ++)
    {
        psiBuf[k] = pfBuf[k];
    }
    free(pfBuf);
    

    您看,最有可能你将有你的电话到 granularizeWithData后,一切都转换回:用:。所以第二个解决办法是做处理虽然从你写的,我想你也不会喜欢后一种方式。

    You see that most likely you will have to convert everything back to short after your call to granularizeWithData: with:. So the second solution would be to do all processing in short although from what you write, I imagine you would not like that latter approach.

    这篇关于在iOS 6中使用AudioFileServices粒子合成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆