如何為Audio Unit 設(shè)置特效

設(shè)置音頻特效使用的是AudioEffectUnit孤个,我們這里實(shí)現(xiàn)的是Reverb(混響)特效惫企。生活中表現(xiàn)的場(chǎng)景就是在不同的空間下有不同的音效。

本篇文章分為以下4個(gè)部分:

  1. 使用ExtAudioFile從文件中讀取音頻數(shù)據(jù)浅侨。
  2. 將數(shù)據(jù)傳遞給AudioEffectUnit處理溪北。
  3. 使用AudioOutputUnit進(jìn)行播放智玻。
  4. 設(shè)置reverbUnit的屬性遂唧。

使用ExtAudioFile讀取文件

ExtAudioFile可以按照我們?cè)O(shè)置的數(shù)據(jù)格式讀取文件,很方便吊奢,具體參照這篇文章盖彭。
ExtAudioFile如何使用

AudioEffectUnit處理數(shù)據(jù)

數(shù)據(jù)流向圖


effect.png

創(chuàng)建AudioUnit

混響效果在iOS上是kAudioUnitSubType_Reverb2,在mac上是kAudioUnitSubType_MatrixReverb

- (void)createAudioUnits {
    AudioComponentDescription ioDesc = {0};
    ioDesc.componentType = kAudioUnitType_Output;
    ioDesc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    ioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    
    AudioComponentDescription reverbDesc = {0};
    reverbDesc.componentType = kAudioUnitType_Effect;
    reverbDesc.componentSubType = kAudioUnitSubType_Reverb2;
    reverbDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    
    OSStatus status;
    AudioComponent outputComp = AudioComponentFindNext(NULL, &ioDesc);
    if (outputComp == NULL) {
        printf("can't get AudioComponent");
    }
    status = AudioComponentInstanceNew(outputComp, &_ioUnit);
    CheckError(status, "creat output unit");
    
    AudioComponent reverbComp = AudioComponentFindNext(NULL, &reverbDesc);
    if (reverbComp == NULL) {
        printf("can't get AudioComponent");
    }
    status = AudioComponentInstanceNew(reverbComp, &_reverbUnit);
    CheckError(status, "creat reverb unit");
}

設(shè)置AudioUnit屬性

AudioOutputUnit的輸入和AudioEffectUnit輸出連接起來(lái)页滚。AudioEffectUnit的輸入就是它的callback召边。

- (void)setupAudioUnits {
    OSStatus status;
    
    // Set the callback method
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = InputRenderCallback;
    callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
    status = AudioUnitSetProperty(_reverbUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Input,
                                  0,
                                  &callbackStruct,
                                  sizeof(callbackStruct));
    CheckError(status, "set callback");
    
    //make connection
    AudioUnitConnection connection;
    connection.sourceAudioUnit    = _reverbUnit;
    connection.sourceOutputNumber = 0;
    connection.destInputNumber    = 0;

    status = AudioUnitSetProperty(_ioUnit,                             // connection destination
                                  kAudioUnitProperty_MakeConnection,   // property key
                                  kAudioUnitScope_Input,               // destination scope
                                  0,                           // destination element
                                  &connection,                 // connection definition
                                  sizeof(connection));
    CheckError(status, "make connection");
}

AudioUnit回調(diào)中填充數(shù)據(jù)

static OSStatus InputRenderCallback(void *inRefCon,
                                    AudioUnitRenderActionFlags *ioActionFlags,
                                    const AudioTimeStamp *inTimeStamp,
                                    UInt32 inBusNumber,
                                    UInt32 inNumberFrames,
                                    AudioBufferList *ioData) {
    ZFAudioUnitEffectPlayer *player = (__bridge ZFAudioUnitEffectPlayer *)inRefCon;

    [player.dataSource readDataToBuffer:ioData length:inNumberFrames];
    
    return noErr;
}

使用AudioOutputUnit進(jìn)行播放

播放和暫停。

- (void)startPlay {
    dispatch_async(_queue, ^{
        OSStatus status;
        status = AudioUnitInitialize(self.reverbUnit);
        CheckError(status, "initialize reverb unit");
        status = AudioUnitInitialize(self.ioUnit);
        CheckError(status, "initialize output unit");
        status = AudioOutputUnitStart(self.ioUnit);
        CheckError(status, "start output unit");
    });
}
- (void)stopPlay {
    dispatch_async(_queue, ^{
        OSStatus status;
        status = AudioOutputUnitStop(self.ioUnit);
        CheckError(status, "stop output unit");
        status = AudioUnitUninitialize(self.ioUnit);
        CheckError(status, "uninitialize output unit");
        status = AudioUnitUninitialize(self.reverbUnit);
        CheckError(status, "uninitialize reverb unit");
    });
}

設(shè)置reverbUnit的屬性

reverbUnit有7個(gè)屬性可以設(shè)置裹驰,都在這里了隧熙。不太懂音律,大家可以運(yùn)行demo自己嘗試一下不同的效果幻林。

- (void)setDryWetMix:(Float32)dryWetMix {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_DryWetMix, kAudioUnitScope_Global, 0, dryWetMix, 0);
}
- (void)setGain:(Float32)gain {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_Gain, kAudioUnitScope_Global, 0, gain, 0);
}
- (void)setMinDelayTime:(Float32)minDelayTime {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_MinDelayTime, kAudioUnitScope_Global, 0, minDelayTime, 0);
}
- (void)setMaxDelayTime:(Float32)maxDelayTime {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_MaxDelayTime, kAudioUnitScope_Global, 0, maxDelayTime, 0);
}
- (void)setDecayTimeAt0Hz:(Float32)decayTimeAt0Hz {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_DecayTimeAt0Hz, kAudioUnitScope_Global, 0, decayTimeAt0Hz, 0);
}
- (void)setDecayTimeAtNyquist:(Float32)decayTimeAtNyquist {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_DecayTimeAtNyquist, kAudioUnitScope_Global, 0, decayTimeAtNyquist, 0);
}
- (void)setRandomizeReflections:(Float32)randomizeReflections {
    AudioUnitSetParameter(_reverbUnit, kReverb2Param_RandomizeReflections, kAudioUnitScope_Global, 0, randomizeReflections, 0);
}

Github地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贞盯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子沪饺,更是在濱河造成了極大的恐慌躏敢,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件随闽,死亡現(xiàn)場(chǎng)離奇詭異父丰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)掘宪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)攘烛,“玉大人魏滚,你說(shuō)我怎么就攤上這事》厥” “怎么了鼠次?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芋齿。 經(jīng)常有香客問(wèn)我腥寇,道長(zhǎng),這世上最難降的妖魔是什么觅捆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任赦役,我火速辦了婚禮,結(jié)果婚禮上栅炒,老公的妹妹穿的比我還像新娘掂摔。我一直安慰自己术羔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布乙漓。 她就那樣靜靜地躺著级历,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叭披。 梳的紋絲不亂的頭發(fā)上寥殖,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音涩蜘,去河邊找鬼嚼贡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛皱坛,可吹牛的內(nèi)容都是我干的编曼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼剩辟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掐场!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起贩猎,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤熊户,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后吭服,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體嚷堡,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年艇棕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蝌戒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沼琉,死狀恐怖北苟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情打瘪,我是刑警寧澤友鼻,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站闺骚,受9級(jí)特大地震影響彩扔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜僻爽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一虫碉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧进泼,春花似錦蔗衡、人聲如沸纤虽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逼纸。三九已至,卻和暖如春济蝉,著一層夾襖步出監(jiān)牢的瞬間杰刽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工王滤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贺嫂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓雁乡,卻偏偏與公主長(zhǎng)得像第喳,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子踱稍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在iOS平臺(tái)上曲饱,所有的音頻框架底層都是基于AudioUnit實(shí)現(xiàn)的。較高層次的音頻框架包括:MediaPlayer...
    阿凡提說(shuō)AI閱讀 3,839評(píng)論 3 7
  • 前言: AudioUnit是什么珠月?在IOS平臺(tái)下扩淀,AudioUnit是一個(gè)底層音頻處理框架,主要功能如下:1啤挎、音頻...
    仙人掌__閱讀 3,886評(píng)論 6 5
  • AudioUnit簡(jiǎn)介 AudioUnit這個(gè)名字取得還是比較形象的驻谆,它的主體就是一系列的unit,不同unit能...
    泥孩兒0107閱讀 4,515評(píng)論 0 2
  • 久違的晴天庆聘,家長(zhǎng)會(huì)胜臊。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí),離放學(xué)已經(jīng)沒(méi)多少時(shí)間了伙判。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)区端。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22
  • 創(chuàng)業(yè)是很多人的夢(mèng)想,多少人為了理想和不甘選擇了創(chuàng)業(yè)來(lái)實(shí)現(xiàn)自我價(jià)值澳腹,我就是其中一個(gè)。 創(chuàng)業(yè)后杨何,我由女人變成了超人酱塔,什...
    亦寶寶閱讀 1,812評(píng)論 4 1