0

我的问题有点棘手,而且我并不完全有经验(我可能会弄错一些术语),所以就这样吧。我声明了一个名为“Singer”的对象的实例。该实例称为“singer1”。“singer1”产生一个音频信号。现在,以下是确定音频信号细节的代码:

OSStatus playbackCallback(void *inRefCon,
                      AudioUnitRenderActionFlags *ioActionFlags,
                      const AudioTimeStamp *inTimeStamp,
                      UInt32 inBusNumber, 
                      UInt32 inNumberFrames,
                      AudioBufferList *ioData) {    

//Singer *me = (Singer *)inRefCon;

static int phase = 0;

for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) {

    int samples = ioData->mBuffers[i].mDataByteSize / sizeof(SInt16);

    SInt16 values[samples];

    float waves;
    float volume=.5;

    for(int j = 0; j < samples; j++) {


        waves = 0;


        waves += sin(kWaveform * 600 * phase)*volume;
        waves += sin(kWaveform * 400 * phase)*volume;
        waves += sin(kWaveform * 200 * phase)*volume;
        waves += sin(kWaveform * 100 * phase)*volume;            

        waves *= 32500 / 4; // <--------- make sure to divide by how many waves you're stacking

        values[j] = (SInt16)waves;
        values[j] += values[j]<<16;

        phase++;

    }

    memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16));

}

return noErr;

}

其中 99% 是借来的代码,所以我对它的工作原理只有一个基本的了解(我不知道 OSStatus 类或方法或其他什么。但是,你会看到这 4 行代码分别为 600、400、200 和100?那些决定了频率。现在,我想做的(现在)是在其中插入我自己的变量来代替常数,我可以随心所欲地改变它。这个变量称为“fr1”。 fr1" 是在头文件中声明的,但是如果我尝试编译,我会收到关于 "fr1" 未声明的错误。目前,我解决此问题的技术如下:在我 #import 东西的下方,我添加了该行

fr1=0.0;//any number will work properly

这种工作,因为代码将编译,如果我告诉它,singer1.fr1 实际上会改变值。现在的问题是这样的:A)即使编译并且指定的音调会播放(0.0 是没有音调),我收到警告“数据定义没有类型或存储类”和“类型默认为'int'在声明'fr1'”。我敢打赌这是因为由于某种原因它没有在头文件中看到我之前的声明(作为浮点数)。但是,同样,如果我忽略这一行,代码将无法编译,因为“fr1 未声明”。B)仅仅因为我改变了 fr1 的值并不意味着歌手 1 将更新存储在“playbackcallback”变量或任何负责更新输出缓冲区的值。也许这可以通过不同的编码来解决?C)即使这确实有效,在暂停/播放音频时仍然存在明显的“间隙”,我需要消除它。这可能意味着对代码进行彻底检查,以便我可以“动态”插入新值而不会破坏任何内容。但是,我之所以努力发布所有这些努力是因为这种方法完全符合我的要求(我可以用数学方法计算一个值,然后它直接进入 DAC,这意味着我将来可以使用它来制作三角形,方等容易波浪)。我已将 Singer.h 和 .m 上传到 pastebin 以供您查看,也许它们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) 暂停/播放音频时,我需要消除它。这可能意味着对代码进行彻底检查,以便我可以“动态”插入新值而不会破坏任何内容。但是,我之所以要努力发布所有这些内容,是因为这种方法完全符合我的要求(我可以用数学方法计算一个值,然后直接进入 DAC,这意味着我将来可以用它来制作三角形,方等容易波浪)。我已将 Singer.h 和 .m 上传到 pastebin 以供您查看,也许它们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) 暂停/播放音频时,我需要消除它。这可能意味着对代码进行彻底检查,以便我可以“动态”插入新值而不会破坏任何内容。但是,我之所以要努力发布所有这些内容,是因为这种方法完全符合我的要求(我可以用数学方法计算一个值,然后直接进入 DAC,这意味着我将来可以用它来制作三角形,方等容易波浪)。我已将 Singer.h 和 .m 上传到 pastebin 以供您查看,也许它们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) 在不破坏任何东西的情况下插入新值。但是,我之所以要努力发布所有这些内容,是因为这种方法完全符合我的要求(我可以用数学方法计算一个值,然后直接进入 DAC,这意味着我将来可以用它来制作三角形,方等容易波浪)。我已将 Singer.h 和 .m 上传到 pastebin 以供您查看,也许它们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) 在不破坏任何东西的情况下插入新值。但是,我之所以要努力发布所有这些内容,是因为这种方法完全符合我的要求(我可以用数学方法计算一个值,然后直接进入 DAC,这意味着我将来可以用它来制作三角形,方等容易波浪)。我已将 Singer.h 和 .m 上传到 pastebin 以供您查看,也许它们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) m to pastebin 为了您的乐趣,也许他们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv) m to pastebin 为了您的乐趣,也许他们会有所帮助。抱歉,我不能发布 2 个 HTML 标签,所以这里是完整链接。(http://pastebin.com/ewhKW2Tk) (http://pastebin.com/CNAT4gFv)

所以,TL;DR,我真正想做的就是能够定义 4 个波的当前方程/值,并经常重新定义它们,而不会在声音中产生间隙。谢谢。(很抱歉,如果帖子令人困惑或偏离了轨道,我很确定确实如此。)

4

1 回答 1

1

我的理解是每次需要重新填充缓冲区时都会调用您的回调函数。所以改变 fr1..fr4 会改变波形,但只有当缓冲区更新时。您不需要停止并重新启动声音来获得更改,但是如果您更改 fr 值,您会注意到音色的突然变化。为了获得音色的平滑过渡,您必须实现一些可以随时间平滑改变 fr 值的东西。调整缓冲区大小将使您能够控制声音对不断变化的 fr 值的响应程度。

您的 fr 未定义问题是由于您的回调是直接的 c 函数。您的 fr 变量被声明为作为 Singer 对象的一部分的 Objective-C 实例变量。默认情况下无法访问它们。

看看这个项目,看看他是如何在他的回调中实现对他的实例变量的访问。基本上,他将对他的实例的引用传递给回调函数,然后通过它访问实例变量。

https://github.com/youpy/dowoscillator

注意:

Sinewave *sineObject = inRefCon;
float freq = sineObject.frequency * 2 * M_PI / samplingRate;

和:

AURenderCallbackStruct input;
input.inputProc = RenderCallback;
input.inputProcRefCon = self;

此外,您需要将回调函数移到 @implementation 块之外,因为它实际上不是 Singer 对象的一部分。

你可以在这里看到这一切:https ://github.com/coryalder/SineWaver

于 2010-11-28T01:49:56.170 回答