我的问题有点棘手,而且我经验不足(我可能会误解一些术语),所以请继续。
我正在声明一个名为“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的值并不意味着singer1将更新存储在“playbackcallback”变量中的值或负责更新输出缓冲区的任何内容。也许可以通过不同的编码来解决? C)即使这确实奏效,在暂停/播放音频时仍然存在明显的“间隙”,我需要消除。这可能意味着对代码进行彻底的检查,以便我可以“动态”插入新值而不会破坏任何内容。但是,我要花所有精力进行发布的原因是因为该方法完全符合我的要求(我可以数学计算一个值,并且直接进入DAC,这意味着我将来可以使用它来制作三角形,正方形等容易波动)。我已经将Singer.h和.m上传到pastebin了,以供您欣赏,也许它们会有所帮助。抱歉,我无法发布2个HTML标签,所以这里是完整链接。
(http://pastebin.com/ewhKW2Tk)
(http://pastebin.com/CNAT4gFv)
因此,TL; DR,我真正想做的就是能够定义4个波形的当前等式/值,并经常重新定义它们,而不会出现声音上的缝隙。
谢谢。 (并且很抱歉,如果帖子令人困惑或偏离正轨,我很确定是这样的。)
最佳答案
我的理解是,每次需要重新填充缓冲区时,都会调用您的回调函数。因此,更改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