| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- //
- // CWVoiceChangePlayCell.m
- // QQVoiceDemo
- //
- // Created by chavez on 2017/10/11.
- // Copyright © 2017年 陈旺. All rights reserved.
- //
- #import "CWVoiceChangePlayCell.h"
- #import "UIView+CWChat.h"
- #import "CWRecordModel.h"
- #import "CWAudioPlayer.h"
- #import "SoundTouchOperation.h"
- static CGFloat const levelWidth = 3.0;
- static CGFloat const levelMargin = 2.0;
- @interface CWVoiceChangePlayCell ()
- @property (nonatomic,weak) UIButton *playButton;
- @property (nonatomic,weak) UIButton *titleButton;
- @property (nonatomic,strong) NSMutableArray *currentLevels; // 当前振幅数组
- @property (nonatomic,strong) NSMutableArray *allLevels; // 所有收集到的振幅,预先保存,用于播放
- @property (nonatomic,assign) NSInteger recordDuration; // 录音时长
- @property (nonatomic,weak) CAShapeLayer *levelLayer; // 振幅layer
- @property (nonatomic,strong) UIBezierPath *levelPath; // 画振幅的path
- @property (nonatomic,weak) UILabel *timeLabel; // 录音时长标签
- @property (nonatomic,assign) CGFloat progressValue;
- @property (nonatomic,weak) CAShapeLayer *circleLayer; // 环形进度条
- @property (nonatomic,strong) NSDictionary *pitchDict;
- @end
- @implementation CWVoiceChangePlayCell
- {
- NSInteger _allCount; // 记录所有振幅的总个数
- NSInteger _callNumbel; // 记录定时器方法调用多少次,根据这个来算秒数(每秒10次)
- NSOperationQueue *_soundTouchQueue;
- CGFloat _tempoValue;
- CGFloat _pitchValue;
- CGFloat _rateValue;
- }
- #pragma mark - lazyLoad
- - (NSDictionary *)pitchDict {
- if (_pitchDict == nil) {
- _pitchDict = @{ASLocalizedString(@"原声"):@0,
- ASLocalizedString(@"萝莉"):@12,
- ASLocalizedString(@"大叔"):@-7,
- ASLocalizedString(@"惊悚"):@-12,
- ASLocalizedString(@"空灵"):@3,
- ASLocalizedString(@"搞怪"):@7,
- };
- }
- return _pitchDict;
- }
- - (NSMutableArray *)allLevels {
- if (_allLevels == nil) {
- _allLevels = [NSMutableArray array];
- }
- return _allLevels;
- }
- - (NSMutableArray *)currentLevels {
- if (_currentLevels == nil) {
- _currentLevels = [NSMutableArray arrayWithArray:@[@0.05,@0.05,@0.05,@0.05,@0.05,@0.05]];
- }
- return _currentLevels;
- }
- - (instancetype)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self initSoundTouchQueue];
- [self setupSubviews];
- _voicePath = [CWRecordModel shareInstance].path;
- }
- return self;
- }
- - (void)initSoundTouchQueue {
- _soundTouchQueue = [[NSOperationQueue alloc] init];
- _soundTouchQueue.maxConcurrentOperationCount = 1;
- }
- - (void)setupSubviews {
- self.backgroundColor = [UIColor whiteColor];
- [self setupPlayButton];
- [self setupTitleButton];
- // [self timeLabel];
- }
- - (void)layoutSubviews {
- self.playButton.center = CGPointMake(self.cw_width / 2.0, self.cw_height / 2.0 - 10);
- self.titleButton.cw_centerX = self.cw_width / 2.0;
- self.titleButton.cw_centerY = (self.cw_height - self.playButton.cw_bottom) / 2 + self.playButton.cw_bottom;
- }
- #pragma mark - setupUI
- - (void)setupPlayButton {
- UIImage *image = [UIImage imageNamed:@"aio_voiceChange_effect_0"];
- UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
- [button setBackgroundImage:image forState:UIControlStateNormal];
- [button setImage:nil forState:UIControlStateNormal];
- [button setImage:[UIImage imageNamed:@"aio_voiceChange_effect_selected"] forState:UIControlStateSelected];
- [button setImage:[UIImage imageNamed:@"aio_voiceChange_effect_pressed"] forState:UIControlStateHighlighted];
- button.frame = CGRectMake(0, 0, image.size.width, image.size.height);
- button.center = CGPointMake(self.cw_width / 2.0, self.cw_height / 2.0 - 10);
- [button addTarget:self action:@selector(playAudio) forControlEvents:UIControlEventTouchUpInside];
- [self addSubview:button];
- self.playButton = button;
- }
- - (void)setupTitleButton {
- UIImage *image = [UIImage imageNamed:@"aio_voiceChange_text_select"];
- UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
- [button setBackgroundImage:nil forState:UIControlStateNormal];
- [button setBackgroundImage:image forState:UIControlStateSelected];
- [button setTitle:ASLocalizedString(@"原声")forState:UIControlStateNormal];
- button.titleLabel.font = [UIFont systemFontOfSize:13];
- [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
- [button setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
- button.frame = CGRectMake(0, self.playButton.cw_bottom + 5, image.size.width, image.size.height);
- button.cw_centerX = self.cw_width / 2.0;
- button.cw_centerY = (self.cw_height - self.playButton.cw_bottom) / 2 + self.playButton.cw_bottom;
- [self addSubview:button];
- self.titleButton = button;
- }
- - (UILabel *)timeLabel {
- if (_timeLabel == nil) {
- UILabel *timeL = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.cw_width, 20)];
- timeL.text = @"0:00";
- timeL.textAlignment = NSTextAlignmentCenter;
- timeL.font = [UIFont systemFontOfSize:12];
- timeL.textColor = [UIColor whiteColor];
- timeL.cw_top = self.playButton.cw_centerY + 5;
- timeL.hidden = YES;
- [self addSubview:timeL];
- _timeLabel = timeL;
- }
- return _timeLabel;
- }
- - (CAShapeLayer *)levelLayer {
- if (_levelLayer == nil) {
- CGFloat width = 6 * levelWidth + 5 * levelMargin;
- CAShapeLayer *layer = [CAShapeLayer layer];
- layer.frame = CGRectMake(self.playButton.cw_centerX - width / 2, self.playButton.cw_centerY - 20, width, 20);
- layer.strokeColor = [UIColor whiteColor].CGColor;
- layer.lineWidth = levelWidth;
- [self.layer addSublayer:layer];
- _levelLayer = layer;
- }
- return _levelLayer;
- }
- - (CAShapeLayer *)circleLayer {
- if (_circleLayer == nil) {
- CAShapeLayer *layer = [CAShapeLayer layer];
- layer.frame = self.playButton.frame;
- layer.strokeColor = [UIColorFromRGBA(20, 120, 211, 1.0) CGColor];
- // layer.strokeColor = [[UIColor blueColor] CGColor];
- layer.fillColor = [UIColor clearColor].CGColor;
- layer.lineWidth = 1.5;
- // layer.backgroundColor = [UIColor redColor].CGColor;
- [self.layer addSublayer:layer];
- _circleLayer = layer;
- }
- return _circleLayer;
- }
- #pragma mark - setter
- - (void)setTitle:(NSString *)title {
- _title = title;
- [self.titleButton setTitle:title forState:UIControlStateNormal];
- [self.playButton setBackgroundImage:[UIImage imageNamed:_imageName] forState:UIControlStateNormal];
- }
- - (void)setProgressValue:(CGFloat)progressValue {
- _progressValue = progressValue;
- [self updateCircleLayer];
- // [self setNeedsDisplay];
- // [self layoutIfNeeded];
- }
- #pragma mark - 按钮点击
- - (void)playAudio {
-
- self.titleButton.selected = !self.playButton.selected;
- self.playButton.selected = !self.playButton.selected;
- // NSLog(ASLocalizedString(@"按钮点击。。。。%zd"),self.playButton.selected);
- __weak typeof(self) weakSelf = self;
- if (self.playButton.selected) {
- if (_playRecordBlock) _playRecordBlock(weakSelf);
- }else {
- if (_endPlayBlock) _endPlayBlock(weakSelf);
- }
-
- }
- #pragma mark - 变声功能
- - (void)playAudioWithPath:(NSString *)path {
- NSData *data = [NSData dataWithContentsOfFile:path];
- MySountTouchConfig config;
- config.sampleRate = 11025;
- config.tempoChange = 0; // -50 - 100
- config.pitch = [self.pitchDict[self.title] intValue]; // -12 - 12
- config.rate = 0; // -50 - 100
-
- SoundTouchOperation *sdop = [[SoundTouchOperation alloc] initWithTarget:self
- action:@selector(playVoiceChange:)
- SoundTouchConfig:config soundFile:data];
- [_soundTouchQueue cancelAllOperations];
- [_soundTouchQueue addOperation:sdop];
- }
- - (void)playVoiceChange:(NSString *)path {
- [[CWAudioPlayer shareInstance] playAudioWith:path];
- self.voicePath = path;
- }
- // 准备播放
- - (void)preparePlayAudio {
- _callNumbel = 0;
-
- _recordDuration = 0;
- [self updateTimeLabel];
-
- _progressValue = 0;
- self.levelLayer.hidden = NO;
- self.timeLabel.hidden = NO;
- self.allLevels = [[CWRecordModel shareInstance].levels mutableCopy];
- [self.currentLevels removeAllObjects];
- _allCount = self.allLevels.count;
- for (NSInteger i = self.allLevels.count - 1 ; i >= self.allLevels.count - 6 ; i--) {
- CGFloat l = 0.05;
- if (i >= 0) {
- l = [self.allLevels[i] floatValue];
- }
- [self.currentLevels addObject:@(l)];
- }
- }
- #pragma mark - 公有方法
- - (void)playingRecord {
- // NSLog(@"playingRecord");
-
- [self preparePlayAudio];
- // 播放音频
- if ([self.title isEqualToString:ASLocalizedString(@"原声")]) {
- [self playVoiceChange:[CWRecordModel shareInstance].path];
- }else {
- [self playAudioWithPath:[CWRecordModel shareInstance].path];
- }
-
- }
- - (void)updateLevels {
- // NSLog(@"updateLevels:::::::::%zd",self.allLevels.count);
-
- CGFloat value = 1 - (CGFloat)self.allLevels.count / _allCount;
-
- if (value == 1 || self.allLevels.count == 0) {
- __weak typeof(self) weakSelf = self;
- if (_endPlayBlock) {
- _endPlayBlock(weakSelf);
- }
- return;
- }
-
- // 振幅更新
- [self updateLevelLayer];
- // 圆形进度条更新
- self.progressValue = value;
-
- _callNumbel++;
- // 刷新10次增加一秒
- if (_callNumbel % 10 == 0) [self addSeconed];
- }
- - (void)endPlay {
- // 取消layer的隐式动画
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- self.levelLayer.hidden = YES;
- [CATransaction commit];
-
- self.timeLabel.hidden = YES;
- self.playButton.selected = NO;
- self.titleButton.selected = NO;
-
- [[CWAudioPlayer shareInstance] stopCurrentAudio]; // 停止播放音频
-
- self.progressValue = 0;
- }
- #pragma mark - 私有方法
- - (void)addSeconed {
- if (_recordDuration == [CWRecordModel shareInstance].duration) {
- // [self.audioTimer invalidate];
- return;
- }
- _recordDuration++;
-
- [self updateTimeLabel];
- }
- - (void)updateTimeLabel {
- NSString *text ;
- if (_recordDuration < 60) {
- text = [NSString stringWithFormat:@"0:%02zd",_recordDuration];
- }else {
- NSInteger minutes = _recordDuration / 60;
- NSInteger seconed = _recordDuration % 60;
- text = [NSString stringWithFormat:@"%zd:%02zd",minutes,seconed];
- }
- self.timeLabel.text = text;
- }
- - (void)updateLevelLayer {
- CGFloat level = [self.allLevels.firstObject floatValue];
- [self.currentLevels removeLastObject];
- [self.currentLevels insertObject:@(level) atIndex:0];
- [self.allLevels removeObjectAtIndex:0];
-
- self.levelPath = [UIBezierPath bezierPath];
- CGFloat height = CGRectGetHeight(self.levelLayer.frame);
- for (int i = 0; i < self.currentLevels.count; i++) {
- CGFloat x = i * (levelWidth + levelMargin) + levelWidth / 2.0;
- CGFloat pathH = [self.currentLevels[i] floatValue] * height;
- CGFloat startY = height / 2.0 - pathH / 2.0;
- CGFloat endY = height / 2.0 + pathH / 2.0;
- [_levelPath moveToPoint:CGPointMake(x, startY)];
- [_levelPath addLineToPoint:CGPointMake(x, endY)];
- }
-
- self.levelLayer.path = _levelPath.CGPath;
- }
- - (void)updateCircleLayer {
- // NSLog(@"==========================%f",_progressValue);
- UIBezierPath *path = [UIBezierPath bezierPath];
- CGFloat width = CGRectGetWidth(self.circleLayer.frame);
- CGFloat startAngle = -M_PI_2;
- CGFloat angle = _progressValue * M_PI * 2;
- CGFloat endAngle = startAngle + angle;
- [path addArcWithCenter:CGPointMake(width / 2.0, width / 2.0) radius:width / 2.0 - 1.0 startAngle:startAngle endAngle:endAngle clockwise:YES];
- self.circleLayer.path = path.CGPath;
- }
- @end
|