objective-c – 在Cocoa中播放正弦波音

objective-c – 在Cocoa中播放正弦波音,第1张

概述(更新:找到答案,见下文.) 我想在Objective-C Cocoa应用程序中播放1 kHz的正弦波音调;我(尝试)将Swift示例转换为Objective-C,但某处必定存在错误,因为结果音调大约为440 Hz而不是1 kHz,并且仅在左侧通道上. 代码: @property (nonatomic, strong) AVAudioEngine *audioEngine;@property ( (更新:找到答案,见下文.)

我想在Objective-C Cocoa应用程序中播放1 kHz的正弦波音调;我(尝试)将Swift示例转换为Objective-C,但某处必定存在错误,因为结果音调大约为440 Hz而不是1 kHz,并且仅在左侧通道上.

代码:

@property (nonatomic,strong) AVAudioEngine *audioEngine;@property (nonatomic,strong) AVAudioPlayerNode *player;@property (nonatomic,strong) AVAudiomixerNode *mixer;@property (nonatomic,strong) AVAudioPCMBuffer *buffer;// -----self.audioEngine = [[AVAudioEngine alloc] init];self.player = [[AVAudioPlayerNode alloc] init];self.mixer = self.audioEngine.mainmixerNode;self.buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[self.player outputFormatForBus:0] frameCapacity:100];self.buffer.frameLength = 100;float amplitude = 0.4;float frequency = 1000;float sampleRate = [[self.mixer outputFormatForBus:0] sampleRate];NSInteger channelCount = [[self.mixer outputFormatForBus:0] channelCount];float *const *floatChannelData = self.buffer.floatChannelData;float *p2 = *floatChannelData;NSLog(@"Sine generator: sample rate = %.1f,%ld channels,frame length = %u.",sampleRate,(long)channelCount,self.buffer.frameLength);for (int i = 0; i < self.buffer.frameLength ; i += channelCount) {    // a = Amplitude    // n = current sample    // r = Sample rate (samples / sec.)    //    // f(n) = a * sin( theta(n) )    // where theta(n) = 2 * M_PI * n / r    float theta = 441.0f * i * 2.0 * M_PI / sampleRate;    float value = sinf(theta);    p2[i] = value * amplitude;}[self.audioEngine attachNode:self.player];[self.audioEngine connect:self.player to:self.mixer format:[self.player outputFormatForBus:0]];[self.audioEngine startAndReturnError:nil];[self.player play];[self.player scheduleBuffer:self.buffer atTime:nil options:AVAudioPlayerNodeBufferLoops completionHandler:nil];

我怀疑float theta = …行中有数学错误,或者我在使用floatChannelData缓冲区时出错了.最初的Swift系列读取:

buffer.floatChannelData.memory[i] = val * 0.5

不确定如何制作floatChannelData的float * const *类型.我的理解是这是一个指向2 x float * const数组的指针. (2因为频道数量,左/右.)

Swift代码的来源是:http://www.tmroyal.com/playing-sounds-in-swift-audioengine.html

如果有人能向我解释缓冲结构,那将是非常好的.

找到了解决方案

问题是双重的.首先,值441.0确实控制了频率.但仅仅改变这一点并没有解决问题;由此产生的音调比正弦更像锯齿状,并找出原因.

因子441和44.1 kHz的采样率,这些值的比率是1:100 – 恰好是缓冲器中的样本数.将441更改为不是整数倍的值会导致“不完整”的正弦波:最后一个样本帧(#100)中的值不为零,这会在循环重新开始时导致急剧下降 – 这听起来像锯齿波.

我不得不将帧缓冲区长度更改为频率 – 采样率比率的精确(或倍数),以便最后一个样本值为(接近)零.

更新的代码:

self.audioEngine = [[AVAudioEngine alloc] init];self.player = [[AVAudioPlayerNode alloc] init];self.mixer = self.audioEngine.mainmixerNode;float sampleRate = [[self.mixer outputFormatForBus:0] sampleRate];AVAudioFrameCount frameBufferLength = floor(sampleRate / self.frequency) * 1;self.buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[self.player outputFormatForBus:0] frameCapacity:frameBufferLength];self.buffer.frameLength = frameBufferLength;NSInteger channelCount = [[self.mixer outputFormatForBus:0] channelCount];float *const *floatChannelData = self.buffer.floatChannelData;    NSLog(@"Sine generator: sample rate = %.1f,self.buffer.frameLength);for (int i = 0; i < self.buffer.frameLength ; i ++) {    float theta = self.frequency * i * 2.0 * M_PI / sampleRate;    float value = sinf(theta);    for (int channelNumber = 0; channelNumber < channelCount ; channelNumber++) {        float * const channelBuffer = floatChannelData[channelNumber];        channelBuffer[i] = value * self.amplitude;    }   }

这样也可以正确处理任意数量的通道.

解决方法 频率部分很简单:在你的θ计算中,文字441.0f控制它,所以只需将其改为你想要的任何东西.

对于单声道问题,您似乎只写一个数据通道:p2 [i] = value * amplitude;如果你对floatChannelData的组成是正确的,那么你想要这个:

float * const * floatChannelData = self.buffer.floatChannelData;float * const left = floatChannelData[0];float * const right = floatChannelData[1];//...// N.B. Changed the incrementfor (int i = 0; i < self.buffer.frameLength ; i++ ) {    // ...    left[i] = value * amplitude;    right[i] = value * amplitude;}

但是,给定for循环中的增量步骤,您的缓冲区可能是交错的(左右声道在同一缓冲区中交替).在这种情况下,你保持循环增量,但是在每一步都写入p2 [i]和p2 [i 1](对于立体声很容易;如果你有更多的通道,你会对这些通道进行内部循环并写入p2 [j]表示j从0到$NUM_CHANNELS).

总结

以上是内存溢出为你收集整理的objective-c – 在Cocoa中播放正弦波音全部内容,希望文章能够帮你解决objective-c – 在Cocoa中播放正弦波音所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1011602.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存