首页 > 系统 > iOS > 正文

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

2020-07-26 02:20:14
字体:
来源:转载
供稿:网友

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表