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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
赞 (0)