2011-10-30 73 views
4

編輯以下Ben的回答音頻 - 建立/生成和發揮純波形

我試圖做的東西,應該是有人認爲是用來與信號處理很容易,但讓我頭疼。我只是試圖產生一個可以播放任意秒數,可能少於或超過一秒(0.1s,0.88s,1.2s,...)的波形聲音。

要產生波浪的聲音,我使用衆所周知的方法:

+ (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 
} 

即與basicaly稱爲:

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赫茲(當然使用adjustedDuration),則無需點擊。仍然用於測試目的,如果我使用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]; 

但仍有一個點擊。

我被告知問題可能是採樣率。但我真的不明白爲什麼。據我所知,採樣率是一秒鐘內定義的採樣數量。所以對我來說,它不依賴於持續時間和頻率。
And ...爲什麼我不應該有0.18s的聲音和44100的樣品質量...

但無論如何......我想象過,如果我在一秒鐘內採樣44100點, 0.18的持續時間應該導致44100 * 0.18個樣本。這是由int frames代表的數字。所以,我試圖與

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

這並不工作,以取代

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

,只是讓聲音更加尖銳。我仍然不明白爲什麼。我認爲這將是一個質量較低的聲音,因爲它們只是更少的樣本。

有人可以幫助我產生任何想要的延遲,在所需的質量和頻率(可能loopable)波聲音?

我敢肯定,聲音(:-))很容易,但我沒有看到實現這一目標的方法。

我試圖把一個NSLog的看到使用的值(日誌沒有保羅的斜坡):

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。如果您有解決方案來實現它,它會爲我節省幾天時間。

+0

向Apple提交缺陷報告。沒有人能使它工作。 – hotpaw2

回答

0

在一般情況下要發揮需要有一個開始和抵消任何合成的聲音坡道應用(又名攻擊衰減),否則你得到的聲音的開始和結束,這可能瞬變聽起來像點擊。

雖然平滑的形狀(如指數或升餘弦)通常是首選,但在幾ms週期內的簡單線性斜坡通常足以消除這種情況。

一個額外的好處是,您不需要確保您的波形開始和結束於零,因爲起始和偏移功能負責這一點。

const int kAttack = (int)(0.005f * sampleRate); // 5 ms attack period (samples) 
const int kDecay = (int)(0.010f * sampleRate); // 10 ms decay period (samples) 

for (int i = 0; i < frames; i++) 
{ 
    float a = gain * sinf((float)i * 2.0f * M_PI * frequency/sampleRate); 
    if (i < kAttack)    // if in attack (onset) period 
    { 
     a *= (float)i/kAttack; // apply linear onset ramp 
    } 
    else if (i > frames - kDecay) // if in decay (offset) period 
    { 
     a *= 1.0f - (float)(i - (frames - kDecay))/kDecay; // apply linear offset ramp 
    }   

    rawSound[i] = a; 
} 
+0

謝謝,我已經在我的代碼中包括了這一點,但這並不能解決問題。還有一個使用0.18s的勾號,如果我使用0.5s或1s,仍然沒有勾號。如果聲音是循環的,那麼可以真正聽到。 – Oliver

+0

爲了確保我們不會錯誤地解決問題,請嘗試在「問題」持續時間內播放無聲緩衝區(所有值爲0.0f),例如0.25秒,看看你是否仍然點擊。 –

+0

我確認。絕對沒有聲音,也不會彈出帶有「問題」持續時間/頻率/採樣率的零填充緩衝區。 – Oliver

4

您選擇的200Hz頻率不是44.1kHz的整數採樣。如果有44100個樣本/秒/ 200個循環/秒,則可以獲得220.5個樣本/週期。所以,任何時候nbWavesNeeded甚至沒有(以抵消一半樣品)的adjustedDuration翻譯成frames具有產生彈出一個小舍入誤差。

(您的編輯至440Hz後問題更糟糕的是,因爲四百四十零分之四萬四千百具有較高的最大公因數)

至於我已經理解了原理,波的頻率是多少向上和有一秒鐘的下行波。持續時間是...持續時間,sampleRate是一秒鐘內有多少次減少。因此,如果我以1,10,50或1000個部分劃分波浪,它總是同一波浪,只是不太精確。

這基本上是正確的。因此在hertz = 440處有「一秒鐘內有440次上下波」,而你的第二次劃分爲44100次切片。一個「上下波」需要多少片? 1 /第440秒,或1 /第四百四您44100個切片,或44100/440這是100.2272727272...因此,如果frames == 100.22727272..然後一個「上下波」的確切端將對應於您的rawSound的確切末端。但frames是一個整數,所以你停在frames = 100,所以你已經縮短了你的波浪。當聲音播放器循環回到0時,它確實想要循環到0.2272727...,但它當然不能。你聽到那是一個流行音樂。

+0

我有一些困難要跟隨你。你能舉幾個例子嗎?我的意思是在我的例子中,在1.0,0.5和0.25和0.1一樣,nbWavesNeeded是偶數。所以如果我理解你的解釋,我不應該有流行音樂。如何根據赫茲值調整sampleRate以防止流行? – Oliver

+0

就我所瞭解的原理而言,波的頻率是一秒鐘內有多少個上下波。持續時間是...持續時間,sampleRate是一秒鐘內有多少次減少。因此,如果我以1,10,50或1000個部分劃分波浪,它總是同一波浪,只是不太精確。所以我不明白你在談論這兩者之間的關係。 – Oliver

+0

呃,抱歉,我沒有跟着你。我明白你說什麼,但...幀是持續時間* sampleRate。並且持續時間被調整以匹配波浪的數量。所以,無論我是在10或44100部分切入,它從0開始,並以0結束。如果最終我在最後削減一個樣本的時間太短,當循環時,第一個值是可能的遺漏值,並且前一個循環的結束。所以循環應該是完美的。不是? – Oliver

1

在iOS上生成純連續音的方式是不使用AVAudioPlayer,並依靠它來正確連接音頻片段,但要使用音頻隊列API或RemoteIO音頻單元,並控制音頻的連續性自己進入回調緩衝區。

+0

問題並不在於連續的聲音。這裏顯然是因爲重複循環,但問題仍然是它沒有循環。我有一種聲音不適合,而且它的末端會產生劃痕。 – Oliver

+0

自從我上次測試以來,情況發生了變化(您可以查看我的上次編輯)。你知道一個關於如何玩AVAudioPlayer而不是AVAudioPlayer的好教程嗎?我被告知OpenHAL,但是我不明白這個詞是否適用於我的項目。我需要一些基本功能,例如播放,停止,掛起,控制聲音電平,自動循環和播放結束時的回調。 – Oliver

+0

@Oliver - 抱歉,Audio Queue和RemoteIO Audio Unit API不像AVAudioPlayer API那麼容易使用。您必須(重新)編寫代碼以允許API調用您的應用程序以獲取所需大小的樣本緩衝區並計算適當的持續時間。我在這裏有一個部分教程:http://www.musingpaw.com/2011/04/iphone-programming-how-to-play-tone-at.html – hotpaw2

0

看到您的編輯和樣本數據後,我有理由相信你避免我在對方的回答與你所選擇的具體數值描述的陷阱。

讓我提出一個替代方案:AVAudioPlayer採用交錯立體聲採樣(因爲numberOfChannels是2),當你提出一個偶數樣本的你以兩倍於預期的頻率聽到兩個音調(一個非常稍微與其他相) 。當你出現一個奇數時(如你的最後一個例子),有一個樣本缺少一個通道導致流行。

這是一個瘋狂的猜測,因爲我不是iOS開發人員,我不明白爲什麼numberOfChannels是隻讀而不是讀寫。

+0

我認爲這是一種錯誤的方式。因爲1.0秒,我有44100個樣本。對於0.1s,我有4410個樣本。兩者都是偶然的,但第一個不會彈出,第二個會彈出。我已經添加和編輯,以調整採樣率,所以一個波需要一個切片數。現在,一個波浪需要一定數量的切片,並且持續時間需要多個波浪。但是這並沒有改變任何事實...... – Oliver

+0

我在我最後一次測試旁邊回到你身邊。你可以看到我最後的編輯。你知道一種比AVAudioPlayer更容易播放聲音的方法嗎?我打算替換我的自定義類的播放器,但是我發現很難理解,找到文檔,以及其他播放聲音的方法。我被告知openHAL,但我不明白我可以如何在我的項目中使用它。你知道一個好的教程嗎? – Oliver