iOS使用音频处理框架The Amazing Audio Engine实现音频录制播放
程序员文章站
2023-08-17 21:55:15
ios 第三方音频框架the amazing audio engine使用,实现音频录制、播放,可设置配乐。
首先看一下效果图:
下面贴上核心控制器代码:...
ios 第三方音频框架the amazing audio engine使用,实现音频录制、播放,可设置配乐。
首先看一下效果图:
下面贴上核心控制器代码:
#import "viewcontroller.h" #import <avfoundation/avfoundation.h> #import "hwprogresshud.h" #import "uiimage+hw.h" #import "aerecorder.h" #import "hwrecordingdrawview.h" #define kmainw [uiscreen mainscreen].bounds.size.width #define kmainh [uiscreen mainscreen].bounds.size.height @interface viewcontroller () @property (nonatomic, strong) aerecorder *recorder; @property (nonatomic, strong) aeaudiocontroller *audiocontroller; @property (nonatomic, strong) aeaudiofileplayer *player; @property (nonatomic, strong) aeaudiofileplayer *backgroundplayer; @property (nonatomic, strong) nstimer *timer; @property (nonatomic, strong) nsmutablearray *soundsource; @property (nonatomic, weak) hwrecordingdrawview *recordingdrawview; @property (nonatomic, weak) uilabel *reclabel; @property (nonatomic, weak) uilabel *recordtimelabel; @property (nonatomic, weak) uilabel *playtimelabel; @property (nonatomic, weak) uibutton *auditionbtn; @property (nonatomic, weak) uibutton *recordbtn; @property (nonatomic, weak) uislider *slider; @property (nonatomic, copy) nsstring *path; @end @implementation viewcontroller - (aeaudiocontroller *)audiocontroller { if (!_audiocontroller) { _audiocontroller = [[aeaudiocontroller alloc] initwithaudiodescription:[aeaudiocontroller noninterleavedfloatstereoaudiodescription] inputenabled:yes]; _audiocontroller.preferredbufferduration = 0.005; _audiocontroller.usemeasurementmode = yes; } return _audiocontroller; } - (nsmutablearray *)soundsource { if (!_soundsource) { _soundsource = [nsmutablearray array]; } return _soundsource; } - (void)viewdidload { [super viewdidload]; [self creatcontrol]; } - (void)creatcontrol { cgfloat marginx = 30.0f; //音频视图 hwrecordingdrawview *recordingdrawview = [[hwrecordingdrawview alloc] initwithframe:cgrectmake(marginx, 80, kmainw - marginx * 2, 100)]; [self.view addsubview:recordingdrawview]; _recordingdrawview = recordingdrawview; //rec uilabel *reclabel = [[uilabel alloc] initwithframe:cgrectmake(marginx, cgrectgetmaxy(recordingdrawview.frame) + 20, 80, 40)]; reclabel.text = @"rec"; reclabel.textcolor = [uicolor redcolor]; [self.view addsubview:reclabel]; _reclabel = reclabel; //录制时间 uilabel *recordtimelabel = [[uilabel alloc] initwithframe:cgrectmake(cgrectgetmaxx(reclabel.frame) + 20, cgrectgetminy(reclabel.frame), 150, 40)]; recordtimelabel.text = @"录制时长:00:00"; [self.view addsubview:recordtimelabel]; _recordtimelabel = recordtimelabel; //播放时间 uilabel *playtimelabel = [[uilabel alloc] initwithframe:cgrectmake(cgrectgetminx(recordtimelabel.frame), cgrectgetmaxy(recordtimelabel.frame), 150, 40)]; playtimelabel.text = @"播放时长:00:00"; playtimelabel.hidden = yes; [self.view addsubview:playtimelabel]; _playtimelabel = playtimelabel; //配乐按钮 nsarray *titlearray = @[@"无配乐", @"夏天", @"阳光海湾"]; cgfloat btnw = 80.0f; cgfloat padding = (kmainw - marginx * 2 - btnw * titlearray.count) / (titlearray.count - 1); for (int i = 0; i < titlearray.count; i++) { cgfloat btnx = marginx + (btnw + padding) * i; uibutton *btn = [[uibutton alloc] initwithframe:cgrectmake(btnx, cgrectgetmaxy(playtimelabel.frame) + 20, btnw, btnw)]; [btn settitle:titlearray[i] forstate:uicontrolstatenormal]; btn.layer.cornerradius = btnw * 0.5; btn.layer.maskstobounds = yes; [btn setbackgroundimage:[uiimage imagewithcolor:[uicolor graycolor]] forstate:uicontrolstatenormal]; [btn setbackgroundimage:[uiimage imagewithcolor:[uicolor orangecolor]] forstate:uicontrolstateselected]; if (i == 0) btn.selected = yes; btn.tag = 100 + i; [btn addtarget:self action:@selector(changebackgroundmusic:) forcontrolevents:uicontroleventtouchupinside]; [self.view addsubview:btn]; } //配乐音量 uilabel *backgroundlabel = [[uilabel alloc] initwithframe:cgrectmake(marginx + 10, cgrectgetmaxy(playtimelabel.frame) + 120, 80, 40)]; backgroundlabel.text = @"配乐音量"; [self.view addsubview:backgroundlabel]; //配乐音量 uislider *slider = [[uislider alloc] initwithframe:cgrectmake(cgrectgetmaxx(backgroundlabel.frame) + 10, cgrectgetminy(backgroundlabel.frame), 210, 40)]; slider.value = 0.4f; [slider addtarget:self action:@selector(slidervaluechanged:) forcontrolevents:uicontroleventvaluechanged]; [self.view addsubview:slider]; _slider = slider; //试听按钮 uibutton *auditionbtn = [[uibutton alloc] initwithframe:cgrectmake(marginx, kmainh - 150, 120, 80)]; auditionbtn.hidden = yes; auditionbtn.backgroundcolor = [uicolor blackcolor]; [auditionbtn settitle:@"试听" forstate:uicontrolstatenormal]; [auditionbtn settitle:@"停止" forstate:uicontrolstateselected]; [auditionbtn addtarget:self action:@selector(auditionbtnonclick:) forcontrolevents:uicontroleventtouchupinside]; [self.view addsubview:auditionbtn]; _auditionbtn = auditionbtn; //录音按钮 uibutton *recordbtn = [[uibutton alloc] initwithframe:cgrectmake(kmainw - marginx - 120, kmainh - 150, 120, 80)]; recordbtn.backgroundcolor = [uicolor blackcolor]; [recordbtn settitle:@"开始" forstate:uicontrolstatenormal]; [recordbtn settitle:@"暂停" forstate:uicontrolstateselected]; [recordbtn addtarget:self action:@selector(recordbtnonclick:) forcontrolevents:uicontroleventtouchupinside]; [self.view addsubview:recordbtn]; _recordbtn = recordbtn; } //配乐按钮点击事件 - (void)changebackgroundmusic:(uibutton *)btn { //更新选中状态 for (int i = 0; i < 3; i++) { uibutton *button = (uibutton *)[self.view viewwithtag:100 + i]; button.selected = no; } btn.selected = yes; //移除之前配乐 if (_backgroundplayer) { [_audiocontroller removechannels:@[_backgroundplayer]]; _backgroundplayer = nil; } nsurl *url; if (btn.tag == 100) { return; }else if (btn.tag == 101) { url = [[nsbundle mainbundle]urlforresource:@"夏天.mp3" withextension:nil]; }else if (btn.tag == 102) { url = [[nsbundle mainbundle]urlforresource:@"阳光海湾.mp3" withextension:nil]; } [self.audiocontroller start:null]; nserror *averror = null; _backgroundplayer = [aeaudiofileplayer audiofileplayerwithurl:url error:&averror]; _backgroundplayer.volume = _slider.value; _backgroundplayer.loop = yes; if (!_backgroundplayer) { [[[uialertview alloc] initwithtitle:@"error" message:[nsstring stringwithformat:@"couldn't start playback: %@", [averror localizeddescription]] delegate:nil cancelbuttontitle:nil otherbuttontitles:@"ok", nil] show]; return; } //放完移除 _backgroundplayer.removeuponfinish = yes; __weak viewcontroller *weakself = self; _backgroundplayer.completionblock = ^{ weakself.backgroundplayer = nil; }; [_audiocontroller addchannels:@[_backgroundplayer]]; } //配乐音量slider滑动事件 - (void)slidervaluechanged:(uislider *)slider { if (_backgroundplayer) _backgroundplayer.volume = slider.value; } //录音按钮点击事件 - (void)recordbtnonclick:(uibutton *)btn { [[avaudiosession sharedinstance] requestrecordpermission:^(bool granted) { if (granted) { //用户同意获取麦克风 dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(.1f * nsec_per_sec)), dispatch_get_main_queue(), ^{ btn.selected = !btn.selected; if (btn.selected) { [self startrecord]; }else { [self finishrecord]; } }); }else { //用户不同意获取麦克风 [hwprogresshud showmessage:@"需要访问您的麦克风,请在“设置-隐私-麦克风”中允许访问。" duration:3.f]; } }]; } //开始录音 - (void)startrecord { _auditionbtn.hidden = yes; [self.audiocontroller start:null]; _recorder = [[aerecorder alloc] initwithaudiocontroller:_audiocontroller]; _path = [self getpath]; nserror *error = null; if ( ![_recorder beginrecordingtofileatpath:_path filetype:kaudiofilem4atype error:&error] ) { [[[uialertview alloc] initwithtitle:@"error" message:[nsstring stringwithformat:@"couldn't start recording: %@", [error localizeddescription]] delegate:nil cancelbuttontitle:nil otherbuttontitles:@"ok", nil] show]; _recorder = nil; return; } [self.soundsource removeallobjects]; [self removetimer]; [self addrecordtimer]; [_audiocontroller addoutputreceiver:_recorder]; [_audiocontroller addinputreceiver:_recorder]; } //结束录音 - (void)finishrecord { _auditionbtn.hidden = no; _reclabel.hidden = no; [self removetimer]; [_recorder finishrecording]; [_audiocontroller removeoutputreceiver:_recorder]; [_audiocontroller removeinputreceiver:_recorder]; _recorder = nil; } //添加录音定时器 - (void)addrecordtimer { self.timer = [nstimer scheduledtimerwithtimeinterval:.2f target:self selector:@selector(recordtimeraction) userinfo:nil repeats:yes]; [[nsrunloop mainrunloop] addtimer:self.timer formode:nsrunloopcommonmodes]; } //录音定时器事件 - (void)recordtimeraction { //获取音频 [catransaction begin]; [catransaction setdisableactions:yes]; float32 inputavg, inputpeak, outputavg, outputpeak; [_audiocontroller inputaveragepowerlevel:&inputavg peakholdlevel:&inputpeak]; [_audiocontroller outputaveragepowerlevel:&outputavg peakholdlevel:&outputpeak]; [self.soundsource insertobject:[nsnumber numberwithfloat:(inputpeak + 18) * 2.8] atindex:0]; [catransaction commit]; _recordingdrawview.pointarray = _soundsource; //rec闪动 _reclabel.hidden = (int)[self.recorder currenttime] % 2 == 1 ? yes : no; //录音时间 nsstring *str = [self strwithtime:[self.recorder currenttime] interval:0.5f]; if ([str intvalue] < 0) str = @"录制时长:00:00"; [self.recordtimelabel settext:[nsstring stringwithformat:@"录制时长:%@", str]]; } //移除定时器 - (void)removetimer { [self.timer invalidate]; self.timer = nil; } //试听按钮点击事件 - (void)auditionbtnonclick:(uibutton *)btn { btn.selected = !btn.selected; if (btn.selected) { [self playrecord]; }else { [self stopplayrecord]; } } //播放录音 - (void)playrecord { //更新界面 _recordbtn.hidden = yes; [_playtimelabel settext:@"播放时长:00:00"]; _playtimelabel.hidden = no; //取消背景音乐 [self changebackgroundmusic:(uibutton *)[self.view viewwithtag:100]]; if (![[nsfilemanager defaultmanager] fileexistsatpath:_path]) return; nserror *error = nil; _player = [aeaudiofileplayer audiofileplayerwithurl:[nsurl fileurlwithpath:_path] error:&error]; if (!_player) { [[[uialertview alloc] initwithtitle:@"error" message:[nsstring stringwithformat:@"couldn't start playback: %@", [error localizeddescription]] delegate:nil cancelbuttontitle:nil otherbuttontitles:@"ok", nil] show]; return; } [self addplaytimer]; _player.removeuponfinish = yes; __weak viewcontroller *weakself = self; _player.completionblock = ^{ weakself.player = nil; weakself.auditionbtn.selected = no; [weakself stopplayrecord]; }; [self.audiocontroller start:null]; [self.audiocontroller addchannels:@[_player]]; } //停止播放录音 - (void)stopplayrecord { _recordbtn.hidden = no; _playtimelabel.hidden = yes; [self removetimer]; if (_player) [_audiocontroller removechannels:@[_player]]; } //添加播放定时器 - (void)addplaytimer { self.timer = [nstimer scheduledtimerwithtimeinterval:1.0f target:self selector:@selector(playtimeraction) userinfo:nil repeats:yes]; [[nsrunloop mainrunloop] addtimer:self.timer formode:nsrunloopcommonmodes]; } //播放定时器事件 - (void)playtimeraction { //播放时间 nsstring *str = [self strwithtime:[_player currenttime] interval:1.f]; if ([str intvalue] < 0) str = @"播放时长:00:00"; [_playtimelabel settext:[nsstring stringwithformat:@"播放时长:%@", str]]; } //录制音频沙盒路径 - (nsstring *)getpath { nsdateformatter *formatter = [[nsdateformatter alloc] init]; [formatter setdateformat:@"yyyymmddhhmmss"]; nsstring *recordname = [nsstring stringwithformat:@"%@.wav", [formatter stringfromdate:[nsdate date]]]; nsstring *path = [[nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject] stringbyappendingpathcomponent:recordname]; return path; } //时长长度转时间字符串 - (nsstring *)strwithtime:(double)time interval:(cgfloat)interval { int minute = (time * interval) / 60; int second = (int)(time * interval) % 60; return [nsstring stringwithformat:@"%02d:%02d", minute, second]; } @end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: VUE脚手架的下载和配置步骤详解