欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS使用音频处理框架The Amazing Audio Engine实现音频录制播放

程序员文章站 2023-12-01 21:13:58
ios 第三方音频框架the amazing audio engine使用,实现音频录制、播放,可设置配乐。 首先看一下效果图: 下面贴上核心控制器代码:...

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。