iOS Audio(音頻)

1. 播放音效

#pragma mark 基本使用
- (void)baseUse
{
    //1. 創(chuàng)建URL地址
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"buyao.wav" withExtension:nil];
    
    //2. 系統(tǒng)音效文件 SystemSoundID = UInt32
    SystemSoundID soundID;
    
    //3. 創(chuàng)建音效文件
    AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
    
    //4. 播放音效文件
    //4.1 不帶震動的播放
    //AudioServicesPlaySystemSound(soundID);
    
    //4.2 帶振動的播放 --> 真機(jī)才有效果
    AudioServicesPlayAlertSound(soundID);
    
    //5. 如果不需要播放了, 需要釋放音效所占用的內(nèi)存
    AudioServicesDisposeSystemSoundID(soundID);
}

2. 簡單封裝

MTAudioTool.h

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@interface MTAudioTools : NSObject
/** 播放系統(tǒng)音效*/
+ (void)playSystemSoundWithURL:(NSURL *)url;
/** 播放震動音效*/
+ (void)playAlertSoundWithURL:(NSURL *)url;
/** 清空音效文件的內(nèi)存*/
+ (void)clearMemory;
@end

MTAudioTool.m


#import "MTAudioTools.h"

/** 緩存字典*/
static NSMutableDictionary *_soundIDDict;

@implementation MTAudioTools

// 只要頭文件參與了編譯調(diào)用
//+ (void)load

/** 緩存字典初始化*/
+ (void)initialize
{
    _soundIDDict = [NSMutableDictionary dictionary];
}

+ (void)playSystemSoundWithURL:(NSURL *)url
{
    // 不帶震動的播放
    AudioServicesPlaySystemSound([self loadSoundIDWithURL:url]);
}

/** 播放震動音效*/
+ (void)playAlertSoundWithURL:(NSURL *)url
{
    // 帶震動的播放
    AudioServicesPlayAlertSound([self loadSoundIDWithURL:url]);

}

#pragma mark 播放音效的公用方法
+ (SystemSoundID)loadSoundIDWithURL:(NSURL *)url
{
    // 思路思路
    // soundID重復(fù)創(chuàng)建 --> soundID每次創(chuàng)建, 就會有對應(yīng)的URL地址產(chǎn)生
    // 可以將創(chuàng)建后的soundID 及 對應(yīng)的URL 進(jìn)行緩存處理
    
    //1. 獲取URL的字符串
    NSString *urlStr = url.absoluteString;
    
    //2. 從緩存字典中根據(jù)URL來取soundID 系統(tǒng)音效文件
    SystemSoundID soundID = [_soundIDDict[urlStr] intValue];
    
    //需要在剛進(jìn)入的時候, 判斷緩存字典是否有url對應(yīng)的soundID
    
    //3. 判斷soundID是否為0, 如果為0, 說明沒有找到, 需要創(chuàng)建
    if (soundID == 0) {
        //3.1 創(chuàng)建音效文件
        AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
        
        //3.2 緩存字典的添加鍵值
        _soundIDDict[urlStr] = @(soundID);
    }
    
    return soundID;
}


/** 清空音效文件的內(nèi)存*/
+ (void)clearMemory
{
    //1. 遍歷字典
    [_soundIDDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        
        //2. 清空音效文件的內(nèi)存
        SystemSoundID soundID = [obj intValue];
        AudioServicesDisposeSystemSoundID(soundID);
    }];
}

@end

ViewController.m

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "MTAudioTools.h"

/**
 1. 導(dǎo)入AVFoundation框架
 2. 創(chuàng)建音效文件
 3. 播放音效文件
 
 音效: 非常短的音樂, 一般來說30秒以內(nèi)的聲音, 都算作音效
 */

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

#pragma mark 點(diǎn)擊播放音效
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //1. 獲取URL地址
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"buyao.wav" withExtension:nil];
    
    //2. 調(diào)用工具類播放音效
    //[MTAudioTools playSystemSoundWithURL:url];
    
    [MTAudioTools playAlertSoundWithURL:url];
    
}

#pragma mark 當(dāng)前控制器收到內(nèi)存警告時會調(diào)用的方法
- (void)didReceiveMemoryWarning
{
    // 局部音效需要在這里進(jìn)行釋放
    [MTAudioTools clearMemory];
    NSLog(@"%s",__func__);
}

@end

3. 音樂播放

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

/**
 1. 需要使用AVFoundatiaon框架
 2. 創(chuàng)建音樂播放器
 3. 根據(jù)需求, 進(jìn)行播放/暫停/停止
 */

@interface ViewController ()
@property (nonatomic, strong) AVAudioPlayer *player;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 創(chuàng)建音樂播放器
    
    //1. 獲取URL路徑
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"我愛你你卻愛著她.mp3" withExtension:nil];
    
    //2. 創(chuàng)建一個error對象
    NSError *error;
    
    //3. 創(chuàng)建音樂播放器
    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    
    if (error) {
        NSLog(@"有錯誤產(chǎn)生");
    }
    
}

- (IBAction)playClick:(id)sender {
    //1. 準(zhǔn)備播放 --> 將音頻文件加載到內(nèi)存中 --> 這句話可以不寫 --> play會隱式調(diào)用prepareToPlay方法. 但是規(guī)范來說, 還是會寫上
    [self.player prepareToPlay];
    
    //2. 開始播放
    [self.player play];
}

- (IBAction)pauseClick:(id)sender {

    // 暫停播放
    [self.player pause];
}

- (IBAction)stopClick:(id)sender {
    // 停止播放
    [self.player stop];
    
    // 歸零操作 / 時間重置 currentTime--> 秒為單位
    self.player.currentTime = 0;
}
@end

4. 錄音

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

/**
 1. 需要使用AVFoundatiaon框架
 2. 創(chuàng)建錄音對象
 3. 根據(jù)需求, 進(jìn)行錄音/暫停/停止
 */

@interface ViewController ()

@property (nonatomic, strong) AVAudioRecorder *recorder;

@property (nonatomic, strong) CADisplayLink *displayLink;

@end

@implementation ViewController

/**
 
 //錄音
 //    //settings  設(shè)置參數(shù)  錄音相關(guān)參數(shù)  聲道  速率  采樣率
 //    NSMutableDictionary *setting = [NSMutableDictionary dictionary];
 //    // 音頻格式
 //    setting[AVFormatIDKey] = @(kAudioFormatAppleIMA4);
 //    // 音頻采樣率
 //    setting[AVSampleRateKey] = @(600.0);
 //    // 音頻通道數(shù)
 //    setting[AVNumberOfChannelsKey] = @(1);
 //    // 線性音頻的位深度
 //    setting[AVLinearPCMBitDepthKey] = @(8);
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 創(chuàng)建錄音對象
    //1. 獲取URL地址 --> 具體的文件名路徑
    //--> 注意之前是獲取資源地址, 這里是指要將錄音存放到哪里
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"recorde.wav"];
    
    //2. 將path字符串轉(zhuǎn)換成NSURL --> file://
    NSURL *url = [NSURL fileURLWithPath:path];
    
    //3. 配置設(shè)置字典
    // 如果傳空, 默認(rèn)就是高質(zhì)量
    // 錄音的參數(shù)值
    NSMutableDictionary *setting = [NSMutableDictionary dictionary];
    
    //4. 創(chuàng)建Error對象 __autoreleasing 可以不加, 加上之后是最標(biāo)準(zhǔn)寫法
    __autoreleasing NSError *error;
    
    //5. 創(chuàng)建錄音對象
    self.recorder = [[AVAudioRecorder alloc] initWithURL:url settings:setting error:&error];
    
//    if (error) {
//        NSLog(@"error");
//    }
    
    //6. 打開分貝的檢測
    self.recorder.meteringEnabled = YES;
    
    //7. 如果要在真機(jī)運(yùn)行, 還需要一個session類, 并且制定分類為錄音
    AVAudioSession *session = [AVAudioSession new];
    [session setCategory:AVAudioSessionCategoryRecord error:nil];
}

- (IBAction)recordClick:(id)sender {
    //1. 準(zhǔn)備錄音
    [self.recorder prepareToRecord];
    
    //2. 開始錄音  --> 如果同一路徑再次錄音, 則會覆蓋之前的文件
    [self.recorder record];
    
    //3. 進(jìn)行分貝的循環(huán)檢測 --> 添加計時器
    [self updateMetering];
}

- (IBAction)pauseClick:(id)sender {
    // 暫停錄音  --> 如果用戶只是暫停了, 應(yīng)該提示用戶進(jìn)行保存操作
    [self.recorder pause];
    
    // 暫停循環(huán)
    self.displayLink.paused = YES;
}

- (IBAction)stopClick:(id)sender {
    // 停止錄音 --> 之后停止錄音時, 最終的錄音文件才會生產(chǎn)
    [self.recorder stop];
    
    // 暫停循環(huán)
    self.displayLink.paused = YES;
    
    NSLog(@"停止錄音");
}

#pragma mark 添加計時器
- (void)updateMetering
{
    // 如果沒有displayLink就創(chuàng)建
    if (self.displayLink == nil) {
        //1. 創(chuàng)建displayLink
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMeter)];
        
        //2. 添加到運(yùn)行循環(huán)中
        [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    }
    
    // 判斷如果暫停了循環(huán), 就打開
    if (self.displayLink.isPaused) {
        self.displayLink.paused = NO;
    }
}

#pragma mark 循環(huán)調(diào)用的方法
- (void)updateMeter
{
    //需求: 自動停止錄音 --> 根據(jù)分貝的大小來判斷
    
    //1. 我們需要獲取分貝信息
    //2. 設(shè)置分貝如果小于某個值, 一定時間后, 自動停止
    
    //1. 更新分貝信息
    [self.recorder updateMeters];
    
    //2. 獲取分貝信息 --> iOS直接傳0
    // 0 ~ -160 , 值最大是0, 最小是-160. 系統(tǒng)返回的是負(fù)值
    CGFloat power = [self.recorder averagePowerForChannel:0];
    
    //3. 實(shí)現(xiàn)2S自動停止
    static NSInteger number;
    
    //displayLink,一秒默認(rèn)是60次, 如果120此的調(diào)用都小于某個分貝值, 我們就可以認(rèn)為要自動停止
    
    //3.1 先判斷用戶是否小于某個分貝值 --> 用戶是否沒說話
    if (power < -30) {
        
        //3.2 如果發(fā)現(xiàn)很安靜, 我們就可以記錄一下, number進(jìn)行疊加
        number++;
        
        //3.3 如果發(fā)現(xiàn)120次了, 都小于設(shè)定的分貝值
        if (number / 60 >= 2) {
            
            //3.4 調(diào)用停止方法
            [self stopClick:nil];
        }
    } else {
        number = 0;
    }
    
    NSLog(@"power: %f",power);
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末且改,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吆寨,更是在濱河造成了極大的恐慌纪吮,老刑警劉巖悼潭,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攘乒,死亡現(xiàn)場離奇詭異设预,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碎乃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門姊扔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梅誓,你說我怎么就攤上這事恰梢。” “怎么了梗掰?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵嵌言,是天一觀的道長。 經(jīng)常有香客問我及穗,道長摧茴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任埂陆,我火速辦了婚禮蓬蝶,結(jié)果婚禮上尘分,老公的妹妹穿的比我還像新娘猜惋。我一直安慰自己丸氛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布著摔。 她就那樣靜靜地躺著缓窜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谍咆。 梳的紋絲不亂的頭發(fā)上禾锤,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音摹察,去河邊找鬼恩掷。 笑死,一個胖子當(dāng)著我的面吹牛供嚎,可吹牛的內(nèi)容都是我干的黄娘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼克滴,長吁一口氣:“原來是場噩夢啊……” “哼逼争!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起劝赔,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤誓焦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后着帽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杂伟,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年仍翰,在試婚紗的時候發(fā)現(xiàn)自己被綠了赫粥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡歉备,死狀恐怖傅是,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蕾羊,我是刑警寧澤喧笔,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站龟再,受9級特大地震影響书闸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜利凑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一浆劲、第九天 我趴在偏房一處隱蔽的房頂上張望嫌术。 院中可真熱鬧,春花似錦牌借、人聲如沸度气。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磷籍。三九已至,卻和暖如春现柠,著一層夾襖步出監(jiān)牢的瞬間院领,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工够吩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留比然,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓周循,卻偏偏與公主長得像强法,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鱼鼓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

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