iphone - 音频 - 构建/生成并播放纯波形

标签 iphone cocoa-touch math audio signal-processing

按照本的回答进行编辑

我正在尝试制作一些对于使用信号处理的人来说应该非常容易的东西,但这让我很头疼。我只是想生成一个可以播放任意秒数的波形声音,可以少于或多于一秒(0.1 秒、0.88 秒、1.2 秒,...)。

为了生成波浪声,我使用了众所周知的方法:

+ (NSData*) WAVSoundForFrequency:(float)frequency duration:(float)seconds sampleRate:(unsigned int)sampleRate gain:(float)gain
{
    int frames = seconds * sampleRate;
    float* rawSound = (float*)malloc(frames*sizeof(float));
    if (rawSound == NULL) return nil;

    for (int i = 0; i < frames; i++)
      rawSound[i] = gain * sinf(i*2*M_PI*frequency/sampleRate);

    // converting to raw sound and returning the whole thing
}

这基本上是通过以下方式调用的:

AVAudioPlayer* player = [self.audioPlayerManager buildSoundFrequency:200 duration:0.18 sampleRate:44100 gain:1.0];
player.volume = 1.0;
player.numberOfLoops = -1;
[player play];

问题是,使用这些参数,波形在最后似乎并不完整,因此它会生成在每个循环中都可以听到的咔嗒声。但是,如果我使用 0.5 秒或 1.0 秒的持续时间和 200 赫兹(当然使用 adjustmentDuration),则不会点击。仍然出于测试目的,如果我使用 400 赫兹或 440 赫兹而不是 200 赫兹,我现在的点击时间为 0.5 秒。

请注意,循环仅用于测试并查看是否有点击。最后,声音应该只在所需的持续时间播放。

我猜测这是因为持续时间不是波周期的整数倍,所以我像这样调整了调用,将所需的持续时间调整为最接近的持续时间,该持续时间是一个周期的倍数想要的频率:

float wantedDuration = 0.18;
float hertz = 200;
int wantedSampleRate = 44100;

// Adjusting wanted duration so the duration contains an entiere number of waves
float oneWaveDurationInSeconds = 1.0/hertz;
int nbWavesNeeded = roundf(wantedDuration/oneWaveDurationInSeconds);
float adjustedDuration = nbWavesNeeded * oneWaveDurationInSeconds;

// Adjusting sample rate so one wave takes an entiere number of samples
float oneSampleDuration = 1.0/wantedSampleRate;

int adjustedSamplerate = wantedSampleRate;
while (YES) {
    oneSampleDuration = 1.0/adjustedSamplerate;
    if (roundf(oneWaveDurationInSeconds/oneSampleDuration) == oneWaveDurationInSeconds/oneSampleDuration) break;
    adjustedSamplerate++;
    NSLog(@"%d", adjustedSamplerate);
}

// Debug
float nbSamplesForOneWave = oneWaveDurationInSeconds / (1.0/adjustedSamplerate);
NSLog(@"nbSamplesForOneWave : %f", nbSamplesForOneWave);

// Execute
MyAudioPlayer* player = [self.manager preloadSoundFrequency:hertz duration:adjustedDuration sampleRate:adjustedSamplerate gain:1.0 
                                                 identifier:@"ii" category:@"Radar"];
player.volume = 1.0;
player.numberOfLoops = -1;
[player play];

但是仍然有咔哒声。

有人告诉我问题可能出在采样率上。但我实在不明白为什么。据我了解,采样率是一秒内定义的样本数。所以对我来说,它不依赖于持续时间或频率。
而且...为什么我不应该拥有 44100 采样质量的 0.18 秒声音...

但无论如何...我想象过,如果我在一秒钟内采样 44100 个点,要求 0.18 的持续时间应该会得到 44100*0.18 个样本。这是由 int 帧 表示的数字。所以我尝试更换

      rawSound[i] = gain * sinf(i*2*M_PI*frequency/sampleRate);

      rawSound[i] = gain * sinf(i*2*M_PI*frequency/frames);

那是行不通的,这只会让声音变得更加尖锐。我仍然不明白为什么。我认为这会是一个质量较差的声音,因为样本较少。

有人可以帮助我以所需的质量和频率生成任何想要的延迟(可能是可循环的)波形声音吗?

我确信这听起来 (:-)) 很容易,但我不知道实现此目标的方法。

我尝试放置 NSLog 来查看使用的值(没有 Paul 斜坡的日志):

    if (i<20 || i > frames-20) NSLog(@"%f", rawSound[i]);

对于 440Hz、44100 采样率、1.0 持续时间(无调整): 没有点击

2011-10-31 01:02:34.110 testAudio[9602:207] 0.000000
2011-10-31 01:02:34.112 testAudio[9602:207] 0.062648
2011-10-31 01:02:34.113 testAudio[9602:207] 0.125051
2011-10-31 01:02:34.114 testAudio[9602:207] 0.186961
2011-10-31 01:02:34.115 testAudio[9602:207] 0.248138
2011-10-31 01:02:34.116 testAudio[9602:207] 0.308339
2011-10-31 01:02:34.116 testAudio[9602:207] 0.367330
2011-10-31 01:02:34.117 testAudio[9602:207] 0.424877
2011-10-31 01:02:34.117 testAudio[9602:207] 0.480755
2011-10-31 01:02:34.118 testAudio[9602:207] 0.534744
2011-10-31 01:02:34.119 testAudio[9602:207] 0.586632
2011-10-31 01:02:34.121 testAudio[9602:207] 0.636216
2011-10-31 01:02:34.121 testAudio[9602:207] 0.683300
2011-10-31 01:02:34.122 testAudio[9602:207] 0.727699
2011-10-31 01:02:34.123 testAudio[9602:207] 0.769240
2011-10-31 01:02:34.123 testAudio[9602:207] 0.807759
2011-10-31 01:02:34.124 testAudio[9602:207] 0.843104
2011-10-31 01:02:34.125 testAudio[9602:207] 0.875137
2011-10-31 01:02:34.126 testAudio[9602:207] 0.903732
2011-10-31 01:02:34.127 testAudio[9602:207] 0.928777
2011-10-31 01:02:34.130 testAudio[9602:207] -0.928790
2011-10-31 01:02:34.130 testAudio[9602:207] -0.903724
2011-10-31 01:02:34.131 testAudio[9602:207] -0.875102
2011-10-31 01:02:34.132 testAudio[9602:207] -0.843167
2011-10-31 01:02:34.132 testAudio[9602:207] -0.807795
2011-10-31 01:02:34.133 testAudio[9602:207] -0.769245
2011-10-31 01:02:34.134 testAudio[9602:207] -0.727667
2011-10-31 01:02:34.135 testAudio[9602:207] -0.683225
2011-10-31 01:02:34.135 testAudio[9602:207] -0.636283
2011-10-31 01:02:34.136 testAudio[9602:207] -0.586658
2011-10-31 01:02:34.137 testAudio[9602:207] -0.534724
2011-10-31 01:02:34.138 testAudio[9602:207] -0.480687
2011-10-31 01:02:34.138 testAudio[9602:207] -0.424978
2011-10-31 01:02:34.139 testAudio[9602:207] -0.367383
2011-10-31 01:02:34.140 testAudio[9602:207] -0.308342
2011-10-31 01:02:34.140 testAudio[9602:207] -0.248087
2011-10-31 01:02:34.141 testAudio[9602:207] -0.186856
2011-10-31 01:02:34.142 testAudio[9602:207] -0.125132
2011-10-31 01:02:34.142 testAudio[9602:207] -0.062676

对于 440Hz、44100 采样率、0.5 持续时间(无调整): 没有点击

2011-10-31 01:04:51.043 testAudio[9714:207] 0.000000
2011-10-31 01:04:51.045 testAudio[9714:207] 0.062648
2011-10-31 01:04:51.047 testAudio[9714:207] 0.125051
2011-10-31 01:04:51.049 testAudio[9714:207] 0.186961
2011-10-31 01:04:51.049 testAudio[9714:207] 0.248138
2011-10-31 01:04:51.050 testAudio[9714:207] 0.308339
2011-10-31 01:04:51.051 testAudio[9714:207] 0.367330
2011-10-31 01:04:51.052 testAudio[9714:207] 0.424877
2011-10-31 01:04:51.053 testAudio[9714:207] 0.480755
2011-10-31 01:04:51.054 testAudio[9714:207] 0.534744
2011-10-31 01:04:51.055 testAudio[9714:207] 0.586632
2011-10-31 01:04:51.055 testAudio[9714:207] 0.636216
2011-10-31 01:04:51.056 testAudio[9714:207] 0.683300
2011-10-31 01:04:51.057 testAudio[9714:207] 0.727699
2011-10-31 01:04:51.059 testAudio[9714:207] 0.769240
2011-10-31 01:04:51.060 testAudio[9714:207] 0.807759
2011-10-31 01:04:51.060 testAudio[9714:207] 0.843104
2011-10-31 01:04:51.061 testAudio[9714:207] 0.875137
2011-10-31 01:04:51.062 testAudio[9714:207] 0.903732
2011-10-31 01:04:51.062 testAudio[9714:207] 0.928777
2011-10-31 01:04:51.064 testAudio[9714:207] -0.928795
2011-10-31 01:04:51.065 testAudio[9714:207] -0.903730
2011-10-31 01:04:51.065 testAudio[9714:207] -0.875109
2011-10-31 01:04:51.066 testAudio[9714:207] -0.843109
2011-10-31 01:04:51.067 testAudio[9714:207] -0.807731
2011-10-31 01:04:51.067 testAudio[9714:207] -0.769253
2011-10-31 01:04:51.068 testAudio[9714:207] -0.727676
2011-10-31 01:04:51.069 testAudio[9714:207] -0.683324
2011-10-31 01:04:51.070 testAudio[9714:207] -0.636199
2011-10-31 01:04:51.070 testAudio[9714:207] -0.586669
2011-10-31 01:04:51.071 testAudio[9714:207] -0.534736
2011-10-31 01:04:51.072 testAudio[9714:207] -0.480806
2011-10-31 01:04:51.072 testAudio[9714:207] -0.424880
2011-10-31 01:04:51.073 testAudio[9714:207] -0.367282
2011-10-31 01:04:51.074 testAudio[9714:207] -0.308355
2011-10-31 01:04:51.074 testAudio[9714:207] -0.248100
2011-10-31 01:04:51.075 testAudio[9714:207] -0.186989
2011-10-31 01:04:51.076 testAudio[9714:207] -0.125025
2011-10-31 01:04:51.077 testAudio[9714:207] -0.062689

对于 440Hz、44100 采样率、0.25 持续时间(无调整): 硬点击

2011-10-31 01:05:25.245 testAudio[9759:207] 0.000000
2011-10-31 01:05:25.247 testAudio[9759:207] 0.062648
2011-10-31 01:05:25.249 testAudio[9759:207] 0.125051
2011-10-31 01:05:25.250 testAudio[9759:207] 0.186961
2011-10-31 01:05:25.251 testAudio[9759:207] 0.248138
2011-10-31 01:05:25.252 testAudio[9759:207] 0.308339
2011-10-31 01:05:25.252 testAudio[9759:207] 0.367330
2011-10-31 01:05:25.253 testAudio[9759:207] 0.424877
2011-10-31 01:05:25.254 testAudio[9759:207] 0.480755
2011-10-31 01:05:25.254 testAudio[9759:207] 0.534744
2011-10-31 01:05:25.255 testAudio[9759:207] 0.586632
2011-10-31 01:05:25.256 testAudio[9759:207] 0.636216
2011-10-31 01:05:25.257 testAudio[9759:207] 0.683300
2011-10-31 01:05:25.257 testAudio[9759:207] 0.727699
2011-10-31 01:05:25.258 testAudio[9759:207] 0.769240
2011-10-31 01:05:25.259 testAudio[9759:207] 0.807759
2011-10-31 01:05:25.260 testAudio[9759:207] 0.843104
2011-10-31 01:05:25.261 testAudio[9759:207] 0.875137
2011-10-31 01:05:25.261 testAudio[9759:207] 0.903732
2011-10-31 01:05:25.262 testAudio[9759:207] 0.928777
2011-10-31 01:05:25.263 testAudio[9759:207] -0.928781
2011-10-31 01:05:25.264 testAudio[9759:207] -0.903727
2011-10-31 01:05:25.264 testAudio[9759:207] -0.875135
2011-10-31 01:05:25.265 testAudio[9759:207] -0.843105
2011-10-31 01:05:25.266 testAudio[9759:207] -0.807763
2011-10-31 01:05:25.267 testAudio[9759:207] -0.769249
2011-10-31 01:05:25.267 testAudio[9759:207] -0.727692
2011-10-31 01:05:25.268 testAudio[9759:207] -0.683296
2011-10-31 01:05:25.269 testAudio[9759:207] -0.636217
2011-10-31 01:05:25.269 testAudio[9759:207] -0.586638
2011-10-31 01:05:25.270 testAudio[9759:207] -0.534756
2011-10-31 01:05:25.271 testAudio[9759:207] -0.480746
2011-10-31 01:05:25.271 testAudio[9759:207] -0.424873
2011-10-31 01:05:25.272 testAudio[9759:207] -0.367332
2011-10-31 01:05:25.273 testAudio[9759:207] -0.308348
2011-10-31 01:05:25.273 testAudio[9759:207] -0.248152
2011-10-31 01:05:25.274 testAudio[9759:207] -0.186952
2011-10-31 01:05:25.275 testAudio[9759:207] -0.125047
2011-10-31 01:05:25.276 testAudio[9759:207] -0.062652

编辑

我已将生成的声音样本(440Hz,444100采样率,0.1秒)写入文件中,并用声音编辑器打开它。多次剪切和粘贴声音以产生更长的声音:播放时没有咔嗒声。通过 AVAudioPlayer 播放的相同声音样本会在每个样本结束时生成喀哒声。所以问题似乎出在 AVAudioPlayer 中,原因我不明白,因为只有某些特定值才会生成这些点击。

编辑

我使用了 wav 生成的文件,并使其与带有循环的 AVAudioPlayer 一起播放:点击
我使用了相同的文件,并使用自定义库使其与 OpenAL 循环播放:不再需要点击。问题是 OpenAL 确实是理解起来的一场噩梦,并且会导致我的声音部分完全重写,只是为了那个糟糕的声音。

问题显然是 AVAudioPlayer 的使用。如果您有一个解决方案使其正常工作,它将节省我的时间。

最佳答案

您选择的 200Hz 频率不是 44.1kHz 样本的整数。如果有 44100 个样本/秒/200 个周期/秒,则您将获得 220.5 个样本/周期。所以任何时候nbWavesNeeded甚至不是(取消一半样本)您的adjustedDuration 翻译成 frames有一个小的舍入误差,会产生流行音乐。

(编辑到 440Hz 后,问题变得更糟,因为 44100/440 具有更高的最大公因数)

As far as I've understood the principle, the wave frequency is how many up-and-down waves there are in a second. the duration is... the duration, and the sampleRate is how many cuts there are in one second. So if I cut a wave in 1, 10, 50 or 1000 parts, it's always the same wave, just less precise.

这基本上是正确的。所以在hertz = 440 “一秒内有 440 个上下波”,并且 sampleRate = 44100第二个被分为 44100 个切片。一次“上下波”需要切多少片? 1/440 秒,或 44100 个切片的 1/440,或 44100 / 440这是 100.2272727272...所以如果 frames == 100.22727272..那么“向上向下波”的确切结束将对应于您的 rawSound 的确切结束。但是frames是一个整数,所以你停在 frames = 100所以你已经缩短了你的波浪。当声音播放器循环回 0 时,它确实想循环到 0.2272727...但当然不能。您听到的是流行音乐。

关于iphone - 音频 - 构建/生成并播放纯波形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7942976/

相关文章:

javascript - NodeJS,多次尝试获取两点之间的 360 度 Angular 失败

iphone - 如何以编程方式检查用户是否登录到应用商店

iphone - 在应用程序内购买没有有效的产品 ID

cocoa-touch - NSNumberFormatter 用于向上舍入浮点值

objective-c - 自定义 UIView 作为 UITableView 委托(delegate)和数据源?

objective-c - 将 nil 添加为 subview 是个坏主意吗?

iphone - 如何向 UILabel 的文本添加渐变,而不是背景?

iphone - 如何更改字典内数组中字典内的值?

algorithm - 采访 qns...在没有任何条件或比较运算符的情况下执行以下操作

python - 重新缩放给定最大值和最小值之间的值,其中最大值为正,最小值为负