├── README.md ├── _config.yml ├── lyricsAnalysis.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── wangshuanglong.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── wangshuanglong.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── lyricsAnalysis.xcscheme │ └── xcschememanagement.plist ├── lyricsAnalysis ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── 114114.png │ │ ├── 120120.png │ │ ├── 4040-1.png │ │ ├── 4040.png │ │ ├── 5858.png │ │ ├── 8080.png │ │ ├── 8787.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m ├── backgroundImage5.jpg ├── main.m ├── screen.jpeg ├── wslAnalyzer.h ├── wslAnalyzer.m ├── wslLrcEach.h ├── wslLrcEach.m ├── 多幸运.mp3 ├── 多幸运.txt ├── 父亲.mp3 └── 父亲.txt ├── lyricsAnalysisTests ├── Info.plist └── lyricsAnalysisTests.m ├── lyricsAnalysisUITests ├── Info.plist └── lyricsAnalysisUITests.m └── 总效果.gif /README.md: -------------------------------------------------------------------------------- 1 | # lyricsAnalysis 2 | iOS音乐播放器之锁屏效果(仿网易云音乐和QQ音乐)+歌词解析 3 | 简书地址:http://www.jianshu.com/p/35ce7e1076d2 4 | 功能描述:锁屏歌曲信息、控制台远程控制音乐播放:暂停/播放、上一首/下一首、快进/快退、列表菜单弹框和拖拽控制台的进度条调节进度(结合了QQ音乐和网易云音乐在锁屏状态下的效果)、歌词解析并随音乐滚动显示。 5 | 6 | ![总效果预览图.gif](http://upload-images.jianshu.io/upload_images/1708447-a83f7e40b01e4f50.gif?imageMogr2/auto-orient/strip) 7 | 8 | **** 9 | 第一部分:锁屏效果包括:锁屏歌曲信息和远程控制音乐播放 10 | ① 锁屏歌曲信息显示 11 | ![锁屏信息预览](http://upload-images.jianshu.io/upload_images/1708447-72e0bb36ac035300.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 12 | ``` 13 | //展示锁屏歌曲信息:图片、歌词、进度、歌曲名、演唱者、专辑、(歌词是绘制在图片上的) 14 | - (void)showLockScreenTotaltime:(float)totalTime andCurrentTime:(float)currentTime andLyricsPoster:(BOOL)isShow{ 15 | 16 | NSMutableDictionary * songDict = [[NSMutableDictionary alloc] init]; 17 | //设置歌曲题目 18 | [songDict setObject:@"多幸运" forKey:MPMediaItemPropertyTitle]; 19 | //设置歌手名 20 | [songDict setObject:@"韩安旭" forKey:MPMediaItemPropertyArtist]; 21 | //设置专辑名 22 | [songDict setObject:@"专辑名" forKey:MPMediaItemPropertyAlbumTitle]; 23 | //设置歌曲时长 24 | [songDict setObject:[NSNumber numberWithDouble:totalTime] forKey:MPMediaItemPropertyPlaybackDuration]; 25 | //设置已经播放时长 26 | [songDict setObject:[NSNumber numberWithDouble:currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; 27 | 28 | UIImage * lrcImage = [UIImage imageNamed:@"backgroundImage5.jpg"]; 29 | if (isShow) { 30 | 31 | //制作带歌词的海报 32 | if (!_lrcImageView) { 33 | _lrcImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 480,800)]; 34 | } 35 | if (!_lockScreenTableView) { 36 | _lockScreenTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 800 - 44 * 7 + 20, 480, 44 * 3) style:UITableViewStyleGrouped]; 37 | _lockScreenTableView.dataSource = self; 38 | _lockScreenTableView.delegate = self; 39 | _lockScreenTableView.separatorStyle = NO; 40 | _lockScreenTableView.backgroundColor = [UIColor clearColor]; 41 | [_lockScreenTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellID"]; 42 | } 43 | //主要为了把歌词绘制到图片上,已达到更新歌词的目的 44 | [_lrcImageView addSubview:self.lockScreenTableView]; 45 | _lrcImageView.image = lrcImage; 46 | _lrcImageView.backgroundColor = [UIColor blackColor]; 47 | 48 | //获取添加了歌词数据的海报图片 49 | UIGraphicsBeginImageContextWithOptions(_lrcImageView.frame.size, NO, 0.0); 50 | CGContextRef context = UIGraphicsGetCurrentContext(); 51 | [_lrcImageView.layer renderInContext:context]; 52 | lrcImage = UIGraphicsGetImageFromCurrentImageContext(); 53 | _lastImage = lrcImage; 54 | UIGraphicsEndImageContext(); 55 | 56 | }else{ 57 | if (_lastImage) { 58 | lrcImage = _lastImage; 59 | } 60 | } 61 | //设置显示的海报图片 62 | [songDict setObject:[[MPMediaItemArtwork alloc] initWithImage:lrcImage] 63 | forKey:MPMediaItemPropertyArtwork]; 64 | //加入正在播放媒体的信息中心 65 | [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songDict]; 66 | 67 | } 68 | 69 | ``` 70 | **** 71 | ② 远程控制音乐播放 72 | ![左侧列表菜单弹出框.PNG](http://upload-images.jianshu.io/upload_images/1708447-afcb25273e2ea214.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 73 | 在此之前需先满足后台播放音乐的条件: 74 | ``` 75 | //后台播放音频设置,需要在Capabilities->Background Modes中勾选Audio,Airplay,and Picture in Picture ,如下图1、2 76 | AVAudioSession *session = [AVAudioSession sharedInstance]; 77 | [session setActive:YES error:nil]; 78 | [session setCategory:AVAudioSessionCategoryPlayback error:nil]; 79 | ``` 80 | ![1.png](http://upload-images.jianshu.io/upload_images/1708447-db2d2d4cc57e27d0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 81 | 82 | 83 | ![2.png](http://upload-images.jianshu.io/upload_images/1708447-7b19e1725fff23e0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 84 | 85 | 在iOS7.1之前, App如果需要在锁屏界面开启和监控远程控制事件,可以通过重写- (void)remoteControlReceivedWithEvent:(UIEvent *)event这个方法来捕获远程控制事件,并根据event.subtype来判别指令意图并作出反应。具体用法如下: 86 | 87 | ``` 88 | //在具体的控制器或其它类中捕获处理远程控制事件,当远程控制事件发生时触发该方法, 该方法属于UIResponder类,iOS 7.1 之前经常用 89 | - (void)remoteControlReceivedWithEvent:(UIEvent *)event{ 90 | NSLog(@"%ld",event.type); 91 | [[NSNotificationCenter defaultCenter] postNotificationName:@"songRemoteControlNotification" object:self userInfo:@{@"eventSubtype":@(event.subtype)}]; 92 | } 93 | 94 | /* iOS 7.1之前*/ 95 | //让App开始接收远程控制事件, 该方法属于UIApplication类 96 | [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 97 | //结束远程控制,需要的时候关闭 98 | // [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 99 | //处理控制台的暂停/播放、上/下一首事件 100 | [[NSNotificationCenter defaultCenter] addObserverForName:@"songRemoteControlNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { 101 | 102 | NSInteger eventSubtype = [notification.userInfo[@"eventSubtype"] integerValue]; 103 | switch (eventSubtype) { 104 | case UIEventSubtypeRemoteControlNextTrack: 105 | NSLog(@"下一首"); 106 | break; 107 | case UIEventSubtypeRemoteControlPreviousTrack: 108 | NSLog(@"上一首"); 109 | break; 110 | case UIEventSubtypeRemoteControlPause: 111 | [self.player pause]; 112 | break; 113 | case UIEventSubtypeRemoteControlPlay: 114 | [self.player play]; 115 | break; 116 | //耳机上的播放暂停 117 | case UIEventSubtypeRemoteControlTogglePlayPause: 118 | NSLog(@"播放或暂停"); 119 | break; 120 | //后退 121 | case UIEventSubtypeRemoteControlBeginSeekingBackward: 122 | break; 123 | case UIEventSubtypeRemoteControlEndSeekingBackward: 124 | NSLog(@"后退"); 125 | break; 126 | //快进 127 | case UIEventSubtypeRemoteControlBeginSeekingForward: 128 | break; 129 | case UIEventSubtypeRemoteControlEndSeekingForward: 130 | NSLog(@"前进"); 131 | break; 132 | default: 133 | break; 134 | } 135 | 136 | }]; 137 | 138 | ``` 139 | 在iOS7.1之后,出现了MPRemoteCommandCenter、MPRemoteCommand 及其相关的一些类 ,锁屏界面开启和监控远程控制事件就更方便了,而且还扩展了一些新功能:网易云音乐的列表菜单弹框功能和QQ音乐的拖拽控制台的进度条调节进度功能等等..... 140 | 官方文档:https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter 141 | ``` 142 | //锁屏界面开启和监控远程控制事件 143 | - (void)createRemoteCommandCenter{ 144 | /**/ 145 | //远程控制命令中心 iOS 7.1 之后 详情看官方文档:https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter 146 | 147 | MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; 148 | 149 | // MPFeedbackCommand对象反映了当前App所播放的反馈状态. MPRemoteCommandCenter对象提供feedback对象用于对媒体文件进行喜欢, 不喜欢, 标记的操作. 效果类似于网易云音乐锁屏时的效果 150 | 151 | //添加喜欢按钮 152 | MPFeedbackCommand *likeCommand = commandCenter.likeCommand; 153 | likeCommand.enabled = YES; 154 | likeCommand.localizedTitle = @"喜欢"; 155 | [likeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 156 | NSLog(@"喜欢"); 157 | return MPRemoteCommandHandlerStatusSuccess; 158 | }]; 159 | //添加不喜欢按钮,假装是“上一首” 160 | MPFeedbackCommand *dislikeCommand = commandCenter.dislikeCommand; 161 | dislikeCommand.enabled = YES; 162 | dislikeCommand.localizedTitle = @"上一首"; 163 | [dislikeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 164 | NSLog(@"上一首"); 165 | return MPRemoteCommandHandlerStatusSuccess; 166 | }]; 167 | //标记 168 | MPFeedbackCommand *bookmarkCommand = commandCenter.bookmarkCommand; 169 | bookmarkCommand.enabled = YES; 170 | bookmarkCommand.localizedTitle = @"标记"; 171 | [bookmarkCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 172 | NSLog(@"标记"); 173 | return MPRemoteCommandHandlerStatusSuccess; 174 | }]; 175 | 176 | // commandCenter.togglePlayPauseCommand 耳机线控的暂停/播放 177 | 178 | [commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 179 | [self.player pause]; 180 | return MPRemoteCommandHandlerStatusSuccess; 181 | }]; 182 | [commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 183 | [self.player play]; 184 | return MPRemoteCommandHandlerStatusSuccess; 185 | }]; 186 | // [commandCenter.previousTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 187 | // NSLog(@"上一首"); 188 | // return MPRemoteCommandHandlerStatusSuccess; 189 | // }]; 190 | 191 | [commandCenter.nextTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 192 | NSLog(@"下一首"); 193 | return MPRemoteCommandHandlerStatusSuccess; 194 | }]; 195 | 196 | //快进 197 | // MPSkipIntervalCommand *skipBackwardIntervalCommand = commandCenter.skipForwardCommand; 198 | // skipBackwardIntervalCommand.preferredIntervals = @[@(54)]; 199 | // skipBackwardIntervalCommand.enabled = YES; 200 | // [skipBackwardIntervalCommand addTarget:self action:@selector(skipBackwardEvent:)]; 201 | 202 | //在控制台拖动进度条调节进度(仿QQ音乐的效果) 203 | [commandCenter.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 204 | CMTime totlaTime = self.player.currentItem.duration; 205 | MPChangePlaybackPositionCommandEvent * playbackPositionEvent = (MPChangePlaybackPositionCommandEvent *)event; 206 | [self.player seekToTime:CMTimeMake(totlaTime.value*playbackPositionEvent.positionTime/CMTimeGetSeconds(totlaTime), totlaTime.timescale) completionHandler:^(BOOL finished) { 207 | }]; 208 | return MPRemoteCommandHandlerStatusSuccess; 209 | }]; 210 | 211 | 212 | } 213 | 214 | -(void)skipBackwardEvent: (MPSkipIntervalCommandEvent *)skipEvent 215 | { 216 | NSLog(@"快进了 %f秒", skipEvent.interval); 217 | } 218 | 219 | ``` 220 | 第二部分:歌词解析 221 | 222 | ![歌词样式.png](http://upload-images.jianshu.io/upload_images/1708447-285ef497840bff48.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 223 | 224 | 根据上图的歌词样式,思路就是:先根据换行符“\n“分割字符串,获得包含每一行歌词字符串的数组,然后解析每一行歌词字符,获得时间点和对应的歌词,再用创建的歌词对象wslLrcEach来存储时间点和歌词,最后得到一个存储wslLrcEach对象的数组。 225 | ``` 226 | //每句歌词对象 227 | @interface wslLrcEach : NSObject 228 | @property(nonatomic, assign) NSUInteger time ; 229 | @property(nonatomic, copy) NSString * lrc ; 230 | @end 231 | ``` 232 | 接下来就是要让歌词随歌曲的进度来滚动显示,主要代码如下: 233 | ``` 234 | self.tableView 显示歌词的 235 | currentTime 当前播放时间点 236 | self.currentRow 当前时间点歌词的位置 237 | 238 | //歌词滚动显示 239 | for ( int i = (int)(self.lrcArray.count - 1); i >= 0 ;i--) { 240 | wslLrcEach * lrc = self.lrcArray[i]; 241 | if (lrc.time < currentTime) { 242 | self.currentRow = i; 243 | [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow: self.currentRow inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; 244 | [self.tableView reloadData]; 245 | break; 246 | } 247 | } 248 | ``` 249 | 250 | >* 更新于2017/9/13 iOS11系统正式发布后 , iOS11上不能像iOS11以下那样锁屏歌词和海报,iOS11把海报显示位置放到了左上方,而且大小变成了头像大小,可能是苹果为了锁屏界面的简洁,只保留了如下图的界面。 251 | 252 | ![iOS11网易云音乐锁屏界面.PNG](http://upload-images.jianshu.io/upload_images/1708447-b928a71e1d44addb.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 253 | 254 | >* 更新于2018/3/7 上面提到 iOS11系统上 ,不能像以往那样显示锁屏歌词了,那锁屏歌词该怎么显示呢,网易云音乐给出了如下图的设计:她是把当前唱到的歌词放到了锁屏的副标题处,随着播放的进度而改变。 255 | ``` 256 | [songDict setObject:@"当前歌词" forKey:MPMediaItemPropertyAlbumTitle]; 257 | ``` 258 | 259 | ![网易云音乐锁屏歌词.PNG](http://upload-images.jianshu.io/upload_images/1708447-3da0ee93b6b68b8e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 260 | 261 | >* 更新于2018/8/2 262 | > 最近有小猿反应了一个Bug:锁屏下暂停播放,过几秒再继续播放,进度条会跳一下,暂停越久跳越猛? 263 | > 查阅资料后发现:我们知道 player 有个 rate 属性,表示播放速率,为 0 的时候表示暂停,为 1.0 的时候表示播放,而MPNowPlayingInfoCenter的nowPlayingInfo也有一个键值MPNowPlayingInfoPropertyPlaybackRate表示速率rate,但是它 与 self.player.rate 是不同步的,也就是说[self.player pause]暂停播放后的速率rate是0,但MPNowPlayingInfoPropertyPlaybackRate还是1,就会造成 在锁屏界面点击了暂停按钮,这个时候进度条表面看起来停止了走动,但是其实还是在计时,所以再点击播放的时候,锁屏界面进度条的光标会发生位置闪动, 所以我们需要在监听播放状态时同步播放速率给MPNowPlayingInfoPropertyPlaybackRate。 264 | 265 | ``` 266 | [songDict setObject:[NSNumber numberWithInteger:rate] forKey:MPNowPlayingInfoPropertyPlaybackRate]; 267 | ``` 268 | 269 | ## Welcome To Follow Me 270 | 271 | > 您的follow和start,是我前进的动力,Thanks♪(・ω・)ノ 272 | > * [简书](https://www.jianshu.com/u/e15d1f644bea) 273 | > * [微博](https://weibo.com/5732733120/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1) 274 | > * [掘金](https://juejin.im/user/5c00d97b6fb9a049fb436288) 275 | > * [CSDN](https://blog.csdn.net/wsl2ls) 276 | > * QQ交流群:835303405 277 | 278 | 欢迎扫描下方二维码关注——iOS开发进阶之路——微信公众号:iOS2679114653 279 | 本公众号是一个iOS开发者们的分享,交流,学习平台,会不定时的发送技术干货,源码,也欢迎大家积极踊跃投稿,(择优上头条) ^_^分享自己开发攻城的过程,心得,相互学习,共同进步,成为攻城狮中的翘楚! 280 | 281 | ![iOS开发进阶之路.jpg](http://upload-images.jianshu.io/upload_images/1708447-c2471528cadd7c86.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 282 | ![亲,赞一下,给个star.jpg](http://upload-images.jianshu.io/upload_images/1708447-60ad604d2d12e1da.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 283 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-leap-day -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 31600A511EE7A01E00B95CF1 /* screen.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 31600A501EE7A01E00B95CF1 /* screen.jpeg */; }; 11 | 3189AD191EE4EBFB007AFCA9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD181EE4EBFB007AFCA9 /* main.m */; }; 12 | 3189AD1C1EE4EBFB007AFCA9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD1B1EE4EBFB007AFCA9 /* AppDelegate.m */; }; 13 | 3189AD1F1EE4EBFB007AFCA9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD1E1EE4EBFB007AFCA9 /* ViewController.m */; }; 14 | 3189AD221EE4EBFB007AFCA9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD201EE4EBFB007AFCA9 /* Main.storyboard */; }; 15 | 3189AD241EE4EBFB007AFCA9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD231EE4EBFB007AFCA9 /* Assets.xcassets */; }; 16 | 3189AD271EE4EBFB007AFCA9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD251EE4EBFB007AFCA9 /* LaunchScreen.storyboard */; }; 17 | 3189AD321EE4EBFB007AFCA9 /* lyricsAnalysisTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD311EE4EBFB007AFCA9 /* lyricsAnalysisTests.m */; }; 18 | 3189AD3D1EE4EBFB007AFCA9 /* lyricsAnalysisUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD3C1EE4EBFB007AFCA9 /* lyricsAnalysisUITests.m */; }; 19 | 3189AD4E1EE4EC22007AFCA9 /* wslAnalyzer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD4B1EE4EC22007AFCA9 /* wslAnalyzer.m */; }; 20 | 3189AD4F1EE4EC22007AFCA9 /* wslLrcEach.m in Sources */ = {isa = PBXBuildFile; fileRef = 3189AD4D1EE4EC22007AFCA9 /* wslLrcEach.m */; }; 21 | 3189AD511EE4F350007AFCA9 /* 父亲.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD501EE4F350007AFCA9 /* 父亲.txt */; }; 22 | 3189AD531EE504A3007AFCA9 /* 父亲.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD521EE504A3007AFCA9 /* 父亲.mp3 */; }; 23 | 3189AD5C1EE54475007AFCA9 /* 多幸运.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD5A1EE54475007AFCA9 /* 多幸运.txt */; }; 24 | 3189AD5D1EE54475007AFCA9 /* 多幸运.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD5B1EE54475007AFCA9 /* 多幸运.mp3 */; }; 25 | 3189AD5F1EE545B4007AFCA9 /* backgroundImage5.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 3189AD5E1EE545B4007AFCA9 /* backgroundImage5.jpg */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 3189AD2E1EE4EBFB007AFCA9 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 3189AD0C1EE4EBFB007AFCA9 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 3189AD131EE4EBFB007AFCA9; 34 | remoteInfo = lyricsAnalysis; 35 | }; 36 | 3189AD391EE4EBFB007AFCA9 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 3189AD0C1EE4EBFB007AFCA9 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 3189AD131EE4EBFB007AFCA9; 41 | remoteInfo = lyricsAnalysis; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 31600A501EE7A01E00B95CF1 /* screen.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = screen.jpeg; sourceTree = ""; }; 47 | 3189AD141EE4EBFB007AFCA9 /* lyricsAnalysis.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = lyricsAnalysis.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 3189AD181EE4EBFB007AFCA9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 3189AD1A1EE4EBFB007AFCA9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 3189AD1B1EE4EBFB007AFCA9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 3189AD1D1EE4EBFB007AFCA9 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 52 | 3189AD1E1EE4EBFB007AFCA9 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 53 | 3189AD211EE4EBFB007AFCA9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 54 | 3189AD231EE4EBFB007AFCA9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 3189AD261EE4EBFB007AFCA9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 56 | 3189AD281EE4EBFB007AFCA9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 3189AD2D1EE4EBFB007AFCA9 /* lyricsAnalysisTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = lyricsAnalysisTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 3189AD311EE4EBFB007AFCA9 /* lyricsAnalysisTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = lyricsAnalysisTests.m; sourceTree = ""; }; 59 | 3189AD331EE4EBFB007AFCA9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 3189AD381EE4EBFB007AFCA9 /* lyricsAnalysisUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = lyricsAnalysisUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 3189AD3C1EE4EBFB007AFCA9 /* lyricsAnalysisUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = lyricsAnalysisUITests.m; sourceTree = ""; }; 62 | 3189AD3E1EE4EBFB007AFCA9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 3189AD4A1EE4EC22007AFCA9 /* wslAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wslAnalyzer.h; sourceTree = ""; }; 64 | 3189AD4B1EE4EC22007AFCA9 /* wslAnalyzer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = wslAnalyzer.m; sourceTree = ""; }; 65 | 3189AD4C1EE4EC22007AFCA9 /* wslLrcEach.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wslLrcEach.h; sourceTree = ""; }; 66 | 3189AD4D1EE4EC22007AFCA9 /* wslLrcEach.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = wslLrcEach.m; sourceTree = ""; }; 67 | 3189AD501EE4F350007AFCA9 /* 父亲.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "父亲.txt"; sourceTree = ""; }; 68 | 3189AD521EE504A3007AFCA9 /* 父亲.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = "父亲.mp3"; sourceTree = ""; }; 69 | 3189AD5A1EE54475007AFCA9 /* 多幸运.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "多幸运.txt"; sourceTree = ""; }; 70 | 3189AD5B1EE54475007AFCA9 /* 多幸运.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = "多幸运.mp3"; sourceTree = ""; }; 71 | 3189AD5E1EE545B4007AFCA9 /* backgroundImage5.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = backgroundImage5.jpg; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 3189AD111EE4EBFB007AFCA9 /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 3189AD2A1EE4EBFB007AFCA9 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 3189AD351EE4EBFB007AFCA9 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | /* End PBXFrameworksBuildPhase section */ 97 | 98 | /* Begin PBXGroup section */ 99 | 3189AD0B1EE4EBFB007AFCA9 = { 100 | isa = PBXGroup; 101 | children = ( 102 | 3189AD161EE4EBFB007AFCA9 /* lyricsAnalysis */, 103 | 3189AD301EE4EBFB007AFCA9 /* lyricsAnalysisTests */, 104 | 3189AD3B1EE4EBFB007AFCA9 /* lyricsAnalysisUITests */, 105 | 3189AD151EE4EBFB007AFCA9 /* Products */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 3189AD151EE4EBFB007AFCA9 /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 3189AD141EE4EBFB007AFCA9 /* lyricsAnalysis.app */, 113 | 3189AD2D1EE4EBFB007AFCA9 /* lyricsAnalysisTests.xctest */, 114 | 3189AD381EE4EBFB007AFCA9 /* lyricsAnalysisUITests.xctest */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 3189AD161EE4EBFB007AFCA9 /* lyricsAnalysis */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 31600A501EE7A01E00B95CF1 /* screen.jpeg */, 123 | 3189AD5E1EE545B4007AFCA9 /* backgroundImage5.jpg */, 124 | 3189AD5A1EE54475007AFCA9 /* 多幸运.txt */, 125 | 3189AD5B1EE54475007AFCA9 /* 多幸运.mp3 */, 126 | 3189AD521EE504A3007AFCA9 /* 父亲.mp3 */, 127 | 3189AD501EE4F350007AFCA9 /* 父亲.txt */, 128 | 3189AD4A1EE4EC22007AFCA9 /* wslAnalyzer.h */, 129 | 3189AD4B1EE4EC22007AFCA9 /* wslAnalyzer.m */, 130 | 3189AD4C1EE4EC22007AFCA9 /* wslLrcEach.h */, 131 | 3189AD4D1EE4EC22007AFCA9 /* wslLrcEach.m */, 132 | 3189AD1A1EE4EBFB007AFCA9 /* AppDelegate.h */, 133 | 3189AD1B1EE4EBFB007AFCA9 /* AppDelegate.m */, 134 | 3189AD1D1EE4EBFB007AFCA9 /* ViewController.h */, 135 | 3189AD1E1EE4EBFB007AFCA9 /* ViewController.m */, 136 | 3189AD201EE4EBFB007AFCA9 /* Main.storyboard */, 137 | 3189AD231EE4EBFB007AFCA9 /* Assets.xcassets */, 138 | 3189AD251EE4EBFB007AFCA9 /* LaunchScreen.storyboard */, 139 | 3189AD281EE4EBFB007AFCA9 /* Info.plist */, 140 | 3189AD171EE4EBFB007AFCA9 /* Supporting Files */, 141 | ); 142 | path = lyricsAnalysis; 143 | sourceTree = ""; 144 | }; 145 | 3189AD171EE4EBFB007AFCA9 /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 3189AD181EE4EBFB007AFCA9 /* main.m */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 3189AD301EE4EBFB007AFCA9 /* lyricsAnalysisTests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 3189AD311EE4EBFB007AFCA9 /* lyricsAnalysisTests.m */, 157 | 3189AD331EE4EBFB007AFCA9 /* Info.plist */, 158 | ); 159 | path = lyricsAnalysisTests; 160 | sourceTree = ""; 161 | }; 162 | 3189AD3B1EE4EBFB007AFCA9 /* lyricsAnalysisUITests */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 3189AD3C1EE4EBFB007AFCA9 /* lyricsAnalysisUITests.m */, 166 | 3189AD3E1EE4EBFB007AFCA9 /* Info.plist */, 167 | ); 168 | path = lyricsAnalysisUITests; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 3189AD131EE4EBFB007AFCA9 /* lyricsAnalysis */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 3189AD411EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysis" */; 177 | buildPhases = ( 178 | 3189AD101EE4EBFB007AFCA9 /* Sources */, 179 | 3189AD111EE4EBFB007AFCA9 /* Frameworks */, 180 | 3189AD121EE4EBFB007AFCA9 /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = lyricsAnalysis; 187 | productName = lyricsAnalysis; 188 | productReference = 3189AD141EE4EBFB007AFCA9 /* lyricsAnalysis.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | 3189AD2C1EE4EBFB007AFCA9 /* lyricsAnalysisTests */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 3189AD441EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysisTests" */; 194 | buildPhases = ( 195 | 3189AD291EE4EBFB007AFCA9 /* Sources */, 196 | 3189AD2A1EE4EBFB007AFCA9 /* Frameworks */, 197 | 3189AD2B1EE4EBFB007AFCA9 /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | 3189AD2F1EE4EBFB007AFCA9 /* PBXTargetDependency */, 203 | ); 204 | name = lyricsAnalysisTests; 205 | productName = lyricsAnalysisTests; 206 | productReference = 3189AD2D1EE4EBFB007AFCA9 /* lyricsAnalysisTests.xctest */; 207 | productType = "com.apple.product-type.bundle.unit-test"; 208 | }; 209 | 3189AD371EE4EBFB007AFCA9 /* lyricsAnalysisUITests */ = { 210 | isa = PBXNativeTarget; 211 | buildConfigurationList = 3189AD471EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysisUITests" */; 212 | buildPhases = ( 213 | 3189AD341EE4EBFB007AFCA9 /* Sources */, 214 | 3189AD351EE4EBFB007AFCA9 /* Frameworks */, 215 | 3189AD361EE4EBFB007AFCA9 /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | 3189AD3A1EE4EBFB007AFCA9 /* PBXTargetDependency */, 221 | ); 222 | name = lyricsAnalysisUITests; 223 | productName = lyricsAnalysisUITests; 224 | productReference = 3189AD381EE4EBFB007AFCA9 /* lyricsAnalysisUITests.xctest */; 225 | productType = "com.apple.product-type.bundle.ui-testing"; 226 | }; 227 | /* End PBXNativeTarget section */ 228 | 229 | /* Begin PBXProject section */ 230 | 3189AD0C1EE4EBFB007AFCA9 /* Project object */ = { 231 | isa = PBXProject; 232 | attributes = { 233 | LastUpgradeCheck = 0830; 234 | ORGANIZATIONNAME = "王双龙"; 235 | TargetAttributes = { 236 | 3189AD131EE4EBFB007AFCA9 = { 237 | CreatedOnToolsVersion = 8.3.1; 238 | DevelopmentTeam = 2N77G66QN3; 239 | ProvisioningStyle = Manual; 240 | SystemCapabilities = { 241 | com.apple.BackgroundModes = { 242 | enabled = 1; 243 | }; 244 | }; 245 | }; 246 | 3189AD2C1EE4EBFB007AFCA9 = { 247 | CreatedOnToolsVersion = 8.3.1; 248 | ProvisioningStyle = Automatic; 249 | TestTargetID = 3189AD131EE4EBFB007AFCA9; 250 | }; 251 | 3189AD371EE4EBFB007AFCA9 = { 252 | CreatedOnToolsVersion = 8.3.1; 253 | ProvisioningStyle = Automatic; 254 | TestTargetID = 3189AD131EE4EBFB007AFCA9; 255 | }; 256 | }; 257 | }; 258 | buildConfigurationList = 3189AD0F1EE4EBFB007AFCA9 /* Build configuration list for PBXProject "lyricsAnalysis" */; 259 | compatibilityVersion = "Xcode 3.2"; 260 | developmentRegion = English; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | en, 264 | Base, 265 | ); 266 | mainGroup = 3189AD0B1EE4EBFB007AFCA9; 267 | productRefGroup = 3189AD151EE4EBFB007AFCA9 /* Products */; 268 | projectDirPath = ""; 269 | projectRoot = ""; 270 | targets = ( 271 | 3189AD131EE4EBFB007AFCA9 /* lyricsAnalysis */, 272 | 3189AD2C1EE4EBFB007AFCA9 /* lyricsAnalysisTests */, 273 | 3189AD371EE4EBFB007AFCA9 /* lyricsAnalysisUITests */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXResourcesBuildPhase section */ 279 | 3189AD121EE4EBFB007AFCA9 /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 3189AD531EE504A3007AFCA9 /* 父亲.mp3 in Resources */, 284 | 3189AD511EE4F350007AFCA9 /* 父亲.txt in Resources */, 285 | 3189AD5D1EE54475007AFCA9 /* 多幸运.mp3 in Resources */, 286 | 3189AD5F1EE545B4007AFCA9 /* backgroundImage5.jpg in Resources */, 287 | 3189AD271EE4EBFB007AFCA9 /* LaunchScreen.storyboard in Resources */, 288 | 3189AD5C1EE54475007AFCA9 /* 多幸运.txt in Resources */, 289 | 3189AD241EE4EBFB007AFCA9 /* Assets.xcassets in Resources */, 290 | 31600A511EE7A01E00B95CF1 /* screen.jpeg in Resources */, 291 | 3189AD221EE4EBFB007AFCA9 /* Main.storyboard in Resources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 3189AD2B1EE4EBFB007AFCA9 /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | 3189AD361EE4EBFB007AFCA9 /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXResourcesBuildPhase section */ 310 | 311 | /* Begin PBXSourcesBuildPhase section */ 312 | 3189AD101EE4EBFB007AFCA9 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 3189AD4E1EE4EC22007AFCA9 /* wslAnalyzer.m in Sources */, 317 | 3189AD1F1EE4EBFB007AFCA9 /* ViewController.m in Sources */, 318 | 3189AD1C1EE4EBFB007AFCA9 /* AppDelegate.m in Sources */, 319 | 3189AD191EE4EBFB007AFCA9 /* main.m in Sources */, 320 | 3189AD4F1EE4EC22007AFCA9 /* wslLrcEach.m in Sources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | 3189AD291EE4EBFB007AFCA9 /* Sources */ = { 325 | isa = PBXSourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | 3189AD321EE4EBFB007AFCA9 /* lyricsAnalysisTests.m in Sources */, 329 | ); 330 | runOnlyForDeploymentPostprocessing = 0; 331 | }; 332 | 3189AD341EE4EBFB007AFCA9 /* Sources */ = { 333 | isa = PBXSourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | 3189AD3D1EE4EBFB007AFCA9 /* lyricsAnalysisUITests.m in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | /* End PBXSourcesBuildPhase section */ 341 | 342 | /* Begin PBXTargetDependency section */ 343 | 3189AD2F1EE4EBFB007AFCA9 /* PBXTargetDependency */ = { 344 | isa = PBXTargetDependency; 345 | target = 3189AD131EE4EBFB007AFCA9 /* lyricsAnalysis */; 346 | targetProxy = 3189AD2E1EE4EBFB007AFCA9 /* PBXContainerItemProxy */; 347 | }; 348 | 3189AD3A1EE4EBFB007AFCA9 /* PBXTargetDependency */ = { 349 | isa = PBXTargetDependency; 350 | target = 3189AD131EE4EBFB007AFCA9 /* lyricsAnalysis */; 351 | targetProxy = 3189AD391EE4EBFB007AFCA9 /* PBXContainerItemProxy */; 352 | }; 353 | /* End PBXTargetDependency section */ 354 | 355 | /* Begin PBXVariantGroup section */ 356 | 3189AD201EE4EBFB007AFCA9 /* Main.storyboard */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | 3189AD211EE4EBFB007AFCA9 /* Base */, 360 | ); 361 | name = Main.storyboard; 362 | sourceTree = ""; 363 | }; 364 | 3189AD251EE4EBFB007AFCA9 /* LaunchScreen.storyboard */ = { 365 | isa = PBXVariantGroup; 366 | children = ( 367 | 3189AD261EE4EBFB007AFCA9 /* Base */, 368 | ); 369 | name = LaunchScreen.storyboard; 370 | sourceTree = ""; 371 | }; 372 | /* End PBXVariantGroup section */ 373 | 374 | /* Begin XCBuildConfiguration section */ 375 | 3189AD3F1EE4EBFB007AFCA9 /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 381 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 382 | CLANG_CXX_LIBRARY = "libc++"; 383 | CLANG_ENABLE_MODULES = YES; 384 | CLANG_ENABLE_OBJC_ARC = YES; 385 | CLANG_WARN_BOOL_CONVERSION = YES; 386 | CLANG_WARN_CONSTANT_CONVERSION = YES; 387 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 388 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INFINITE_RECURSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 394 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 395 | CLANG_WARN_UNREACHABLE_CODE = YES; 396 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 397 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 398 | COPY_PHASE_STRIP = NO; 399 | DEBUG_INFORMATION_FORMAT = dwarf; 400 | ENABLE_STRICT_OBJC_MSGSEND = YES; 401 | ENABLE_TESTABILITY = YES; 402 | GCC_C_LANGUAGE_STANDARD = gnu99; 403 | GCC_DYNAMIC_NO_PIC = NO; 404 | GCC_NO_COMMON_BLOCKS = YES; 405 | GCC_OPTIMIZATION_LEVEL = 0; 406 | GCC_PREPROCESSOR_DEFINITIONS = ( 407 | "DEBUG=1", 408 | "$(inherited)", 409 | ); 410 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 411 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 412 | GCC_WARN_UNDECLARED_SELECTOR = YES; 413 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 414 | GCC_WARN_UNUSED_FUNCTION = YES; 415 | GCC_WARN_UNUSED_VARIABLE = YES; 416 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 417 | MTL_ENABLE_DEBUG_INFO = YES; 418 | ONLY_ACTIVE_ARCH = YES; 419 | SDKROOT = iphoneos; 420 | TARGETED_DEVICE_FAMILY = "1,2"; 421 | }; 422 | name = Debug; 423 | }; 424 | 3189AD401EE4EBFB007AFCA9 /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | ALWAYS_SEARCH_USER_PATHS = NO; 428 | CLANG_ANALYZER_NONNULL = YES; 429 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 430 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 431 | CLANG_CXX_LIBRARY = "libc++"; 432 | CLANG_ENABLE_MODULES = YES; 433 | CLANG_ENABLE_OBJC_ARC = YES; 434 | CLANG_WARN_BOOL_CONVERSION = YES; 435 | CLANG_WARN_CONSTANT_CONVERSION = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 443 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 444 | CLANG_WARN_UNREACHABLE_CODE = YES; 445 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 446 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 447 | COPY_PHASE_STRIP = NO; 448 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 449 | ENABLE_NS_ASSERTIONS = NO; 450 | ENABLE_STRICT_OBJC_MSGSEND = YES; 451 | GCC_C_LANGUAGE_STANDARD = gnu99; 452 | GCC_NO_COMMON_BLOCKS = YES; 453 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 455 | GCC_WARN_UNDECLARED_SELECTOR = YES; 456 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 457 | GCC_WARN_UNUSED_FUNCTION = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 460 | MTL_ENABLE_DEBUG_INFO = NO; 461 | SDKROOT = iphoneos; 462 | TARGETED_DEVICE_FAMILY = "1,2"; 463 | VALIDATE_PRODUCT = YES; 464 | }; 465 | name = Release; 466 | }; 467 | 3189AD421EE4EBFB007AFCA9 /* Debug */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 471 | CODE_SIGN_IDENTITY = "iPhone Developer: qu xg (E3B8HDH8KA)"; 472 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: qu xg (E3B8HDH8KA)"; 473 | DEVELOPMENT_TEAM = 2N77G66QN3; 474 | INFOPLIST_FILE = lyricsAnalysis/Info.plist; 475 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 476 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 477 | PRODUCT_BUNDLE_IDENTIFIER = com.chinadaily.ChinaDaily; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | PROVISIONING_PROFILE = "32971796-ca4a-476c-9423-2e14ca28b7dc"; 480 | PROVISIONING_PROFILE_SPECIFIER = "News for iPhone"; 481 | }; 482 | name = Debug; 483 | }; 484 | 3189AD431EE4EBFB007AFCA9 /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 488 | CODE_SIGN_IDENTITY = "iPhone Developer: qu xg (E3B8HDH8KA)"; 489 | DEVELOPMENT_TEAM = 2N77G66QN3; 490 | INFOPLIST_FILE = lyricsAnalysis/Info.plist; 491 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 492 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 493 | PRODUCT_BUNDLE_IDENTIFIER = com.chinadaily.ChinaDaily; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | PROVISIONING_PROFILE = "32971796-ca4a-476c-9423-2e14ca28b7dc"; 496 | PROVISIONING_PROFILE_SPECIFIER = "News for iPhone"; 497 | }; 498 | name = Release; 499 | }; 500 | 3189AD451EE4EBFB007AFCA9 /* Debug */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | BUNDLE_LOADER = "$(TEST_HOST)"; 504 | INFOPLIST_FILE = lyricsAnalysisTests/Info.plist; 505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 506 | PRODUCT_BUNDLE_IDENTIFIER = com.chinaDaily.lyricsAnalysisTests; 507 | PRODUCT_NAME = "$(TARGET_NAME)"; 508 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/lyricsAnalysis.app/lyricsAnalysis"; 509 | }; 510 | name = Debug; 511 | }; 512 | 3189AD461EE4EBFB007AFCA9 /* Release */ = { 513 | isa = XCBuildConfiguration; 514 | buildSettings = { 515 | BUNDLE_LOADER = "$(TEST_HOST)"; 516 | INFOPLIST_FILE = lyricsAnalysisTests/Info.plist; 517 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 518 | PRODUCT_BUNDLE_IDENTIFIER = com.chinaDaily.lyricsAnalysisTests; 519 | PRODUCT_NAME = "$(TARGET_NAME)"; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/lyricsAnalysis.app/lyricsAnalysis"; 521 | }; 522 | name = Release; 523 | }; 524 | 3189AD481EE4EBFB007AFCA9 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | INFOPLIST_FILE = lyricsAnalysisUITests/Info.plist; 528 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 529 | PRODUCT_BUNDLE_IDENTIFIER = com.chinaDaily.lyricsAnalysisUITests; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | TEST_TARGET_NAME = lyricsAnalysis; 532 | }; 533 | name = Debug; 534 | }; 535 | 3189AD491EE4EBFB007AFCA9 /* Release */ = { 536 | isa = XCBuildConfiguration; 537 | buildSettings = { 538 | INFOPLIST_FILE = lyricsAnalysisUITests/Info.plist; 539 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 540 | PRODUCT_BUNDLE_IDENTIFIER = com.chinaDaily.lyricsAnalysisUITests; 541 | PRODUCT_NAME = "$(TARGET_NAME)"; 542 | TEST_TARGET_NAME = lyricsAnalysis; 543 | }; 544 | name = Release; 545 | }; 546 | /* End XCBuildConfiguration section */ 547 | 548 | /* Begin XCConfigurationList section */ 549 | 3189AD0F1EE4EBFB007AFCA9 /* Build configuration list for PBXProject "lyricsAnalysis" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 3189AD3F1EE4EBFB007AFCA9 /* Debug */, 553 | 3189AD401EE4EBFB007AFCA9 /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | 3189AD411EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysis" */ = { 559 | isa = XCConfigurationList; 560 | buildConfigurations = ( 561 | 3189AD421EE4EBFB007AFCA9 /* Debug */, 562 | 3189AD431EE4EBFB007AFCA9 /* Release */, 563 | ); 564 | defaultConfigurationIsVisible = 0; 565 | defaultConfigurationName = Release; 566 | }; 567 | 3189AD441EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysisTests" */ = { 568 | isa = XCConfigurationList; 569 | buildConfigurations = ( 570 | 3189AD451EE4EBFB007AFCA9 /* Debug */, 571 | 3189AD461EE4EBFB007AFCA9 /* Release */, 572 | ); 573 | defaultConfigurationIsVisible = 0; 574 | defaultConfigurationName = Release; 575 | }; 576 | 3189AD471EE4EBFB007AFCA9 /* Build configuration list for PBXNativeTarget "lyricsAnalysisUITests" */ = { 577 | isa = XCConfigurationList; 578 | buildConfigurations = ( 579 | 3189AD481EE4EBFB007AFCA9 /* Debug */, 580 | 3189AD491EE4EBFB007AFCA9 /* Release */, 581 | ); 582 | defaultConfigurationIsVisible = 0; 583 | defaultConfigurationName = Release; 584 | }; 585 | /* End XCConfigurationList section */ 586 | }; 587 | rootObject = 3189AD0C1EE4EBFB007AFCA9 /* Project object */; 588 | } 589 | -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/project.xcworkspace/xcuserdata/wangshuanglong.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis.xcodeproj/project.xcworkspace/xcuserdata/wangshuanglong.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/xcuserdata/wangshuanglong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/xcuserdata/wangshuanglong.xcuserdatad/xcschemes/lyricsAnalysis.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /lyricsAnalysis.xcodeproj/xcuserdata/wangshuanglong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | lyricsAnalysis.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3189AD131EE4EBFB007AFCA9 16 | 17 | primary 18 | 19 | 20 | 3189AD2C1EE4EBFB007AFCA9 21 | 22 | primary 23 | 24 | 25 | 3189AD371EE4EBFB007AFCA9 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /lyricsAnalysis/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // lyricsAnalysis 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /lyricsAnalysis/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // lyricsAnalysis 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | 20 | return YES; 21 | } 22 | 23 | //在具体的控制器或其它类中捕获处理远程控制事件,当远程控制事件发生时触发该方法, 该方法属于UIResponder类 24 | //- (void)remoteControlReceivedWithEvent:(UIEvent *)event{ 25 | // NSLog(@"%ld",event.type); 26 | // [[NSNotificationCenter defaultCenter] postNotificationName:@"songRemoteControlNotification" object:self userInfo:@{@"eventSubtype":@(event.subtype)}]; 27 | //} 28 | 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 33 | } 34 | 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application { 37 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application { 43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application { 53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/114114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/114114.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/120120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/120120.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/4040-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/4040-1.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/4040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/4040.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/5858.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/5858.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/8080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/8080.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/8787.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/8787.png -------------------------------------------------------------------------------- /lyricsAnalysis/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "4040.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "idiom" : "iphone", 11 | "size" : "20x20", 12 | "scale" : "3x" 13 | }, 14 | { 15 | "size" : "29x29", 16 | "idiom" : "iphone", 17 | "filename" : "5858.png", 18 | "scale" : "2x" 19 | }, 20 | { 21 | "size" : "29x29", 22 | "idiom" : "iphone", 23 | "filename" : "8787.png", 24 | "scale" : "3x" 25 | }, 26 | { 27 | "size" : "40x40", 28 | "idiom" : "iphone", 29 | "filename" : "8080.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "size" : "40x40", 34 | "idiom" : "iphone", 35 | "filename" : "120120.png", 36 | "scale" : "3x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "114114.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "size" : "20x20", 51 | "idiom" : "ipad", 52 | "filename" : "4040-1.png", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "idiom" : "ipad", 57 | "size" : "20x20", 58 | "scale" : "2x" 59 | }, 60 | { 61 | "idiom" : "ipad", 62 | "size" : "29x29", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "idiom" : "ipad", 67 | "size" : "29x29", 68 | "scale" : "2x" 69 | }, 70 | { 71 | "idiom" : "ipad", 72 | "size" : "40x40", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "idiom" : "ipad", 77 | "size" : "40x40", 78 | "scale" : "2x" 79 | }, 80 | { 81 | "idiom" : "ipad", 82 | "size" : "76x76", 83 | "scale" : "1x" 84 | }, 85 | { 86 | "idiom" : "ipad", 87 | "size" : "76x76", 88 | "scale" : "2x" 89 | }, 90 | { 91 | "idiom" : "ipad", 92 | "size" : "83.5x83.5", 93 | "scale" : "2x" 94 | } 95 | ], 96 | "info" : { 97 | "version" : 1, 98 | "author" : "xcode" 99 | } 100 | } -------------------------------------------------------------------------------- /lyricsAnalysis/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /lyricsAnalysis/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /lyricsAnalysis/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | 黑凤梨 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIBackgroundModes 26 | 27 | audio 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /lyricsAnalysis/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // lyricsAnalysis 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ViewController : UIViewController 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /lyricsAnalysis/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // lyricsAnalysis 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "wslAnalyzer.h" 11 | #import "wslLrcEach.h" 12 | #import 13 | #import 14 | 15 | #define SONGNAME @"多幸运" 16 | 17 | @interface ViewController () 18 | { 19 | id _playerTimeObserver; 20 | BOOL _isDragging; 21 | UIImage * _lastImage;//最后一次锁屏之后的歌词海报 22 | 23 | } 24 | //歌词数组 25 | @property (nonatomic , strong) NSMutableArray * lrcArray; 26 | @property (nonatomic, strong) UITableView * tableView; 27 | @property (nonatomic, strong) AVPlayer * player; 28 | 29 | //当前歌词所在位置 30 | @property (nonatomic,assign) NSInteger currentRow; 31 | 32 | //用来显示锁屏歌词 33 | @property (nonatomic, strong) UITableView * lockScreenTableView; 34 | //锁屏图片视图,用来绘制带歌词的image 35 | @property (nonatomic, strong) UIImageView * lrcImageView;; 36 | 37 | @end 38 | 39 | @implementation ViewController 40 | 41 | - (void)viewDidLoad { 42 | [super viewDidLoad]; 43 | 44 | [self getLrcArray]; 45 | 46 | [self.player play]; 47 | 48 | [self playControl]; 49 | 50 | [self.view addSubview:self.tableView]; 51 | //添加远程锁屏控制 52 | [self createRemoteCommandCenter]; 53 | 54 | } 55 | 56 | //锁屏界面开启和监控远程控制事件 57 | - (void)createRemoteCommandCenter{ 58 | /**/ 59 | //远程控制命令中心 iOS 7.1 之后 详情看官方文档:https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter 60 | 61 | MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; 62 | 63 | // MPFeedbackCommand对象反映了当前App所播放的反馈状态. MPRemoteCommandCenter对象提供feedback对象用于对媒体文件进行喜欢, 不喜欢, 标记的操作. 效果类似于网易云音乐锁屏时的效果 64 | 65 | //添加喜欢按钮 66 | MPFeedbackCommand *likeCommand = commandCenter.likeCommand; 67 | likeCommand.enabled = YES; 68 | likeCommand.localizedTitle = @"喜欢"; 69 | [likeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 70 | NSLog(@"喜欢"); 71 | return MPRemoteCommandHandlerStatusSuccess; 72 | }]; 73 | //添加不喜欢按钮,假装是“上一首” 74 | MPFeedbackCommand *dislikeCommand = commandCenter.dislikeCommand; 75 | dislikeCommand.enabled = YES; 76 | dislikeCommand.localizedTitle = @"上一首"; 77 | [dislikeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 78 | NSLog(@"上一首"); 79 | return MPRemoteCommandHandlerStatusSuccess; 80 | }]; 81 | //标记 82 | MPFeedbackCommand *bookmarkCommand = commandCenter.bookmarkCommand; 83 | bookmarkCommand.enabled = YES; 84 | bookmarkCommand.localizedTitle = @"标记"; 85 | [bookmarkCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 86 | NSLog(@"标记"); 87 | return MPRemoteCommandHandlerStatusSuccess; 88 | }]; 89 | 90 | // commandCenter.togglePlayPauseCommand 耳机线控的暂停/播放 91 | __weak typeof(self) weakSelf = self; 92 | [commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 93 | [weakSelf.player pause]; 94 | return MPRemoteCommandHandlerStatusSuccess; 95 | }]; 96 | [commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 97 | [weakSelf.player play]; 98 | return MPRemoteCommandHandlerStatusSuccess; 99 | }]; 100 | // [commandCenter.previousTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 101 | // NSLog(@"上一首"); 102 | // return MPRemoteCommandHandlerStatusSuccess; 103 | // }]; 104 | 105 | [commandCenter.nextTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 106 | NSLog(@"下一首"); 107 | return MPRemoteCommandHandlerStatusSuccess; 108 | }]; 109 | 110 | //快进 111 | // MPSkipIntervalCommand *skipBackwardIntervalCommand = commandCenter.skipForwardCommand; 112 | // skipBackwardIntervalCommand.preferredIntervals = @[@(54)]; 113 | // skipBackwardIntervalCommand.enabled = YES; 114 | // [skipBackwardIntervalCommand addTarget:self action:@selector(skipBackwardEvent:)]; 115 | 116 | //在控制台拖动进度条调节进度(仿QQ音乐的效果) 117 | [commandCenter.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) { 118 | CMTime totlaTime = weakSelf.player.currentItem.duration; 119 | MPChangePlaybackPositionCommandEvent * playbackPositionEvent = (MPChangePlaybackPositionCommandEvent *)event; 120 | [weakSelf.player seekToTime:CMTimeMake(totlaTime.value*playbackPositionEvent.positionTime/CMTimeGetSeconds(totlaTime), totlaTime.timescale) completionHandler:^(BOOL finished) { 121 | }]; 122 | return MPRemoteCommandHandlerStatusSuccess; 123 | }]; 124 | 125 | 126 | } 127 | 128 | -(void)skipBackwardEvent: (MPSkipIntervalCommandEvent *)skipEvent 129 | { 130 | NSLog(@"快进了 %f秒", skipEvent.interval); 131 | } 132 | 133 | //移除观察者 134 | - (void)removeObserver{ 135 | 136 | [self.player removeTimeObserver:_playerTimeObserver]; 137 | _playerTimeObserver = nil; 138 | // self.player = nil; 139 | 140 | MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; 141 | [commandCenter.likeCommand removeTarget:self]; 142 | [commandCenter.dislikeCommand removeTarget:self]; 143 | [commandCenter.bookmarkCommand removeTarget:self]; 144 | [commandCenter.nextTrackCommand removeTarget:self]; 145 | [commandCenter.skipForwardCommand removeTarget:self]; 146 | [commandCenter.changePlaybackPositionCommand removeTarget:self]; 147 | commandCenter = nil; 148 | } 149 | #pragma mark -- Help Methods 150 | 151 | //获得歌词数组 152 | - (void)getLrcArray{ 153 | wslAnalyzer * analyzer = [[wslAnalyzer alloc] init]; 154 | NSString * path = [[NSBundle mainBundle] pathForResource:SONGNAME ofType:@"txt"]; 155 | self.lrcArray = [analyzer analyzerLrcBylrcString:[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]]; 156 | } 157 | //在具体的控制器或其它类中捕获处理远程控制事件,当远程控制事件发生时触发该方法, 该方法属于UIResponder类,iOS 7.1 之前经常用 158 | - (void)remoteControlReceivedWithEvent:(UIEvent *)event{ 159 | NSLog(@"%ld",event.type); 160 | [[NSNotificationCenter defaultCenter] postNotificationName:@"songRemoteControlNotification" object:self userInfo:@{@"eventSubtype":@(event.subtype)}]; 161 | } 162 | 163 | //播放控制和监测 164 | - (void)playControl{ 165 | 166 | //后台播放音频设置,需要在Capabilities->Background Modes中勾选Audio,Airplay,and Picture in Picture 167 | AVAudioSession *session = [AVAudioSession sharedInstance]; 168 | [session setActive:YES error:nil]; 169 | [session setCategory:AVAudioSessionCategoryPlayback error:nil]; 170 | 171 | 172 | __weak ViewController * weakSelf = self; 173 | _playerTimeObserver = [weakSelf.player addPeriodicTimeObserverForInterval:CMTimeMake(0.1*30, 30) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { 174 | 175 | CGFloat currentTime = CMTimeGetSeconds(time); 176 | 177 | CMTime total = weakSelf.player.currentItem.duration; 178 | CGFloat totalTime = CMTimeGetSeconds(total); 179 | 180 | if (!_isDragging) { 181 | 182 | //歌词滚动显示 183 | for ( int i = (int)(self.lrcArray.count - 1); i >= 0 ;i--) { 184 | wslLrcEach * lrc = self.lrcArray[i]; 185 | if (lrc.time < currentTime) { 186 | self.currentRow = i; 187 | NSIndexPath * currentIndexPath = [NSIndexPath indexPathForRow: self.currentRow inSection:0]; 188 | [self.tableView scrollToRowAtIndexPath:currentIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; 189 | [self.tableView reloadData]; 190 | [self.lockScreenTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow: self. currentRow inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; 191 | [self.lockScreenTableView reloadData]; 192 | break; 193 | } 194 | } 195 | } 196 | 197 | //监听锁屏状态 lock=1则为锁屏状态 198 | uint64_t locked; 199 | __block int token = 0; 200 | notify_register_dispatch("com.apple.springboard.lockstate",&token,dispatch_get_main_queue(),^(int t){ 201 | }); 202 | notify_get_state(token, &locked); 203 | 204 | //监听屏幕点亮状态 screenLight = 1则为变暗关闭状态 205 | uint64_t screenLight; 206 | __block int lightToken = 0; 207 | notify_register_dispatch("com.apple.springboard.hasBlankedScreen",&lightToken,dispatch_get_main_queue(),^(int t){ 208 | }); 209 | notify_get_state(lightToken, &screenLight); 210 | 211 | BOOL isShowLyricsPoster = NO; 212 | // NSLog(@"screenLight=%llu locked=%llu",screenLight,locked); 213 | if (screenLight == 0 && locked == 1) { 214 | //点亮且锁屏时 215 | isShowLyricsPoster = YES; 216 | }else if(screenLight){ 217 | return; 218 | } 219 | 220 | //展示锁屏歌曲信息,上面监听屏幕锁屏和点亮状态的目的是为了提高效率 221 | [self showLockScreenTotaltime:totalTime andCurrentTime:currentTime andRate:weakSelf.player.rate andLyricsPoster:isShowLyricsPoster]; 222 | 223 | }]; 224 | 225 | /* iOS 7.1之前 226 | //让App开始接收远程控制事件, 该方法属于UIApplication类 227 | [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 228 | //结束远程控制,需要的时候关闭 229 | // [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 230 | //处理控制台的暂停/播放、上/下一首事件 231 | [[NSNotificationCenter defaultCenter] addObserverForName:@"songRemoteControlNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { 232 | 233 | NSInteger eventSubtype = [notification.userInfo[@"eventSubtype"] integerValue]; 234 | switch (eventSubtype) { 235 | case UIEventSubtypeRemoteControlNextTrack: 236 | NSLog(@"下一首"); 237 | break; 238 | case UIEventSubtypeRemoteControlPreviousTrack: 239 | NSLog(@"上一首"); 240 | break; 241 | case UIEventSubtypeRemoteControlPause: 242 | [self.player pause]; 243 | break; 244 | case UIEventSubtypeRemoteControlPlay: 245 | [self.player play]; 246 | break; 247 | //耳机上的播放暂停 248 | case UIEventSubtypeRemoteControlTogglePlayPause: 249 | NSLog(@"播放或暂停"); 250 | break; 251 | //后退 252 | case UIEventSubtypeRemoteControlBeginSeekingBackward: 253 | break; 254 | case UIEventSubtypeRemoteControlEndSeekingBackward: 255 | NSLog(@"后退"); 256 | break; 257 | //快进 258 | case UIEventSubtypeRemoteControlBeginSeekingForward: 259 | break; 260 | case UIEventSubtypeRemoteControlEndSeekingForward: 261 | NSLog(@"前进"); 262 | break; 263 | default: 264 | break; 265 | } 266 | 267 | }]; 268 | */ 269 | 270 | } 271 | 272 | //展示锁屏歌曲信息:图片、歌词、进度、演唱者 播放速率 273 | - (void)showLockScreenTotaltime:(float)totalTime andCurrentTime:(float)currentTime andRate:(NSInteger)rate andLyricsPoster:(BOOL)isShow{ 274 | 275 | NSMutableDictionary * songDict = [[NSMutableDictionary alloc] init]; 276 | //设置歌曲题目 277 | [songDict setObject:@"多幸运" forKey:MPMediaItemPropertyTitle]; 278 | //设置歌手名 279 | [songDict setObject:@"韩安旭" forKey:MPMediaItemPropertyArtist]; 280 | //设置专辑名 281 | [songDict setObject:@"专辑名" forKey:MPMediaItemPropertyAlbumTitle]; 282 | //设置歌曲时长 283 | [songDict setObject:[NSNumber numberWithDouble:totalTime] forKey:MPMediaItemPropertyPlaybackDuration]; 284 | //设置已经播放时长 285 | [songDict setObject:[NSNumber numberWithDouble:currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; 286 | //设置播放速率 287 | //注意:MPNowPlayingInfoCenter的rate 与 self.player.rate 是不同步的,也就是说[self.player pause]暂停播放后的速率rate是0,但MPNowPlayingInfoCenter的rate还是1,就会造成 在锁屏界面点击了暂停按钮,这个时候进度条表面看起来停止了走动,但是其实还是在计时,所以再点击播放的时候,锁屏界面进度条的光标会发生位置闪动, 所以我们需要在暂停或播放时保持播放速率一致 288 | [songDict setObject:[NSNumber numberWithInteger:rate] forKey:MPNowPlayingInfoPropertyPlaybackRate]; 289 | 290 | UIImage * lrcImage = [UIImage imageNamed:@"backgroundImage5.jpg"]; 291 | if (isShow) { 292 | 293 | //制作带歌词的海报 294 | if (!_lrcImageView) { 295 | _lrcImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 480,800)]; 296 | } 297 | if (!_lockScreenTableView) { 298 | _lockScreenTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 800 - 44 * 7 + 20, 480, 44 * 3) style:UITableViewStyleGrouped]; 299 | _lockScreenTableView.dataSource = self; 300 | _lockScreenTableView.delegate = self; 301 | _lockScreenTableView.separatorStyle = NO; 302 | _lockScreenTableView.backgroundColor = [UIColor clearColor]; 303 | [_lockScreenTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellID"]; 304 | } 305 | //主要为了把歌词绘制到图片上,已达到更新歌词的目的 306 | [_lrcImageView addSubview:self.lockScreenTableView]; 307 | _lrcImageView.image = lrcImage; 308 | _lrcImageView.backgroundColor = [UIColor blackColor]; 309 | 310 | //获取添加了歌词数据的海报图片 311 | UIGraphicsBeginImageContextWithOptions(_lrcImageView.frame.size, NO, 0.0); 312 | CGContextRef context = UIGraphicsGetCurrentContext(); 313 | [_lrcImageView.layer renderInContext:context]; 314 | lrcImage = UIGraphicsGetImageFromCurrentImageContext(); 315 | _lastImage = lrcImage; 316 | UIGraphicsEndImageContext(); 317 | 318 | }else{ 319 | if (_lastImage) { 320 | lrcImage = _lastImage; 321 | } 322 | } 323 | //设置显示的海报图片 324 | [songDict setObject:[[MPMediaItemArtwork alloc] initWithImage:lrcImage] 325 | forKey:MPMediaItemPropertyArtwork]; 326 | 327 | 328 | [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songDict]; 329 | 330 | } 331 | 332 | #pragma mark -- Getter 333 | 334 | - (UITableView *)tableView{ 335 | 336 | if (_tableView == nil) { 337 | 338 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height ) style:UITableViewStyleGrouped]; 339 | _tableView.dataSource = self; 340 | _tableView.delegate = self; 341 | _tableView.estimatedRowHeight = 0; 342 | _tableView.estimatedSectionFooterHeight = 0; 343 | _tableView.estimatedSectionHeaderHeight = 0; 344 | 345 | UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; 346 | imageView.image = [UIImage imageNamed:@"backgroundImage5.jpg"]; 347 | _tableView.backgroundView = imageView; 348 | _tableView.separatorStyle = NO; 349 | [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellID"]; 350 | 351 | } 352 | 353 | return _tableView; 354 | } 355 | 356 | - (AVPlayer *)player{ 357 | 358 | if (_player == nil) { 359 | NSString * path = [[NSBundle mainBundle] pathForResource:SONGNAME ofType:@"mp3"]; 360 | _player = [[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:path]]; 361 | } 362 | return _player; 363 | } 364 | 365 | 366 | 367 | #pragma mark -- UITableViewDelegate 368 | 369 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 370 | 371 | return _lrcArray.count; 372 | } 373 | 374 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 375 | 376 | UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cellID" forIndexPath:indexPath]; 377 | wslLrcEach * lrcEach = _lrcArray[indexPath.row]; 378 | cell.textLabel.text = lrcEach.lrc; 379 | cell.textLabel.textAlignment = NSTextAlignmentCenter; 380 | cell.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; 381 | cell.textLabel.backgroundColor = [UIColor clearColor]; 382 | if (self.currentRow == indexPath.row) { 383 | cell.textLabel.textColor = [UIColor greenColor]; 384 | }else{ 385 | cell.textLabel.textColor = [UIColor whiteColor]; 386 | } 387 | 388 | return cell; 389 | } 390 | 391 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ 392 | _isDragging = YES; 393 | } 394 | 395 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ 396 | if (!decelerate) { 397 | _isDragging = NO; 398 | } 399 | } 400 | 401 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ 402 | _isDragging = NO; 403 | } 404 | 405 | - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{ 406 | 407 | } 408 | 409 | - (void)dealloc{ 410 | [self removeObserver]; 411 | } 412 | 413 | 414 | - (BOOL)shouldAutorotate { 415 | return NO; 416 | } 417 | 418 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 419 | return UIInterfaceOrientationMaskPortrait; //只支持这一个方向(正常的方向) 420 | } 421 | 422 | 423 | 424 | - (void)didReceiveMemoryWarning { 425 | [super didReceiveMemoryWarning]; 426 | // Dispose of any resources that can be recreated. 427 | } 428 | 429 | 430 | @end 431 | -------------------------------------------------------------------------------- /lyricsAnalysis/backgroundImage5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/backgroundImage5.jpg -------------------------------------------------------------------------------- /lyricsAnalysis/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // lyricsAnalysis 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 王双龙. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lyricsAnalysis/screen.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/screen.jpeg -------------------------------------------------------------------------------- /lyricsAnalysis/wslAnalyzer.h: -------------------------------------------------------------------------------- 1 | // 2 | // wslAnalyzer.h 3 | // 歌词解析1 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface wslAnalyzer : NSObject 12 | 13 | @property(nonatomic,strong)NSMutableArray * lrcArray; 14 | 15 | //返回包含每一句歌词信息的数组 16 | -(NSMutableArray *)analyzerLrcByPath:(NSString *)path; 17 | 18 | -(NSMutableArray *)analyzerLrcBylrcString:(NSString *)string; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /lyricsAnalysis/wslAnalyzer.m: -------------------------------------------------------------------------------- 1 | // 2 | // wslAnalyzer.m 3 | // 歌词解析1 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved.// 7 | 8 | #import "wslAnalyzer.h" 9 | #import "wslLrcEach.h" 10 | 11 | @implementation wslAnalyzer 12 | 13 | -(NSMutableArray *)lrcArray 14 | { 15 | if (_lrcArray == nil) { 16 | _lrcArray = [[NSMutableArray alloc] init]; 17 | }return _lrcArray; 18 | } 19 | 20 | -(NSMutableArray *)analyzerLrcByPath:(NSString *)path 21 | { 22 | 23 | [self analyzerLrc:[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]]; 24 | 25 | return self.lrcArray; 26 | } 27 | 28 | -(NSMutableArray *)analyzerLrcBylrcString:(NSString *)string{ 29 | 30 | [self analyzerLrc:string]; 31 | 32 | return self.lrcArray; 33 | } 34 | 35 | //根据换行符\n分割字符串,获得包含每一句歌词的数组 36 | -(void)analyzerLrc:(NSString *)lrcConnect 37 | { 38 | 39 | NSArray * lrcConnectArray = [lrcConnect componentsSeparatedByString:@"\n"]; 40 | 41 | NSMutableArray * lrcConnectArray1 =[[NSMutableArray alloc] initWithArray: lrcConnectArray ]; 42 | 43 | for (NSUInteger i = 0; i < [lrcConnectArray1 count] ;i++ ) { 44 | if ([lrcConnectArray1[i] length] == 0 ) { 45 | [lrcConnectArray1 removeObjectAtIndex:i]; 46 | i--; 47 | } 48 | } 49 | 50 | // NSMutableArray * realLrcArray = [self deleteNoUseInfo:lrcConnectArray1]; 51 | [self analyzerEachLrc:lrcConnectArray1]; 52 | 53 | } 54 | //删除没有用的字符 55 | -(NSMutableArray *)deleteNoUseInfo:(NSMutableArray *)lrcmArray 56 | { 57 | for (NSUInteger i = 0; i < [lrcmArray count] ; i++) 58 | { 59 | unichar ch = [lrcmArray[i] characterAtIndex:1]; 60 | if(!isnumber(ch)){ 61 | [lrcmArray removeObjectAtIndex:i]; 62 | i--; 63 | } 64 | } 65 | return lrcmArray; 66 | } 67 | 68 | //解析每一行歌词字符,获得时间点和对应的歌词 69 | -(void)analyzerEachLrc:(NSMutableArray *)lrcConnectArray 70 | { 71 | for (NSUInteger i = 0; i < [lrcConnectArray count] ; i++) { 72 | 73 | NSArray * eachLrcArray = [lrcConnectArray[i] componentsSeparatedByString:@"]"]; 74 | 75 | NSString * lrc = [eachLrcArray lastObject]; 76 | 77 | NSDateFormatter *df = [[NSDateFormatter alloc] init]; 78 | [df setDateFormat:@"[mm:ss.SS"]; 79 | 80 | NSDate * date1 = [df dateFromString:eachLrcArray[0] ]; 81 | NSDate *date2 = [df dateFromString:@"[00:00.00"]; 82 | NSTimeInterval interval1 = [date1 timeIntervalSince1970]; 83 | NSTimeInterval interval2 = [date2 timeIntervalSince1970]; 84 | interval1 -= interval2; 85 | if (interval1 < 0) { 86 | interval1 *= -1; 87 | } 88 | 89 | //如果时间点对应的歌词为空就不加入歌词数组 90 | // if (lrc.length == 0 || [lrc isEqualToString:@"\r"] || [lrc isEqualToString:@"\n"]) { 91 | // continue; 92 | // } 93 | wslLrcEach * eachLrc = [[wslLrcEach alloc] init]; 94 | eachLrc.lrc = lrc; 95 | eachLrc.time = interval1; 96 | [self.lrcArray addObject:eachLrc]; 97 | 98 | } 99 | } 100 | 101 | 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /lyricsAnalysis/wslLrcEach.h: -------------------------------------------------------------------------------- 1 | // 2 | // wslLrcEach.h 3 | // 4 | // Created by 王双龙 on 2017/6/5. 5 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | //每句歌词对象 11 | @interface wslLrcEach : NSObject 12 | @property(nonatomic,assign) NSUInteger time; 13 | @property(nonatomic,copy)NSString * lrc; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /lyricsAnalysis/wslLrcEach.m: -------------------------------------------------------------------------------- 1 | // 2 | // wslLrcEach.m 3 | // 4 | // Created by 王双龙 on 2017/6/5. 5 | // Copyright © 2017年 https://github.com/wslcmk All rights reserved. 6 | // 7 | 8 | #import "wslLrcEach.h" 9 | 10 | @implementation wslLrcEach 11 | 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /lyricsAnalysis/多幸运.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/多幸运.mp3 -------------------------------------------------------------------------------- /lyricsAnalysis/多幸运.txt: -------------------------------------------------------------------------------- 1 | 2 | [00:00.91]《多幸运》 3 | [00:03.82]词:刘家泽 4 | [00:07.03]曲:胜屿 5 | [00:10.24]演唱:韩安旭 6 | [00:12.95]听众:doubleDragon 7 | [00:19.68]在亿万人海相遇 8 | [00:21.43]有同样默契 9 | [00:24.24]是多么不容易 10 | [00:27.30]你懂得我的固执 11 | [00:30.26]我懂你脾气 12 | [00:32.77]两颗心在靠近 13 | [00:35.42]等不及解释我的心情 14 | [00:39.34]怕错过爱上你的时机 15 | [00:43.60]浪漫已经 准备就绪 16 | [00:48.17]全新的旅行 17 | [00:52.68]多幸运 18 | [00:54.44]在最美的年纪 19 | [00:57.40]遇见你 20 | [00:59.46]没有遗憾和可惜 21 | [01:01.46]抱紧你 22 | [01:03.77]用尽全部力气 23 | [01:05.47]不让幸福逃离 24 | [01:10.24]多幸运 25 | [01:12.20]爱你这件事情 26 | [01:14.36]成为我 27 | [01:16.16]今生最对的决定 28 | [01:18.83]我相信 29 | [01:20.63]你就是那唯一 30 | [01:23.14]愿陪你到底 31 | [01:28.41]多幸运 遇见了你 32 | [01:31.58]多幸运 爱上了你 33 | [01:33.43]多幸运 能在一起 34 | [01:35.79]多幸运 遇见了你 35 | [01:40.06]多幸运 爱上了你 36 | [01:42.41]多幸运 能在一起 37 | [01:45.17]我很幸运,遇见,爱上,能在一起的她 -- Doris 38 | [01:46.92]在亿万人海相遇 39 | [01:48.92]有同样默契 40 | [01:51.39]是多么不容易 41 | [01:53.34]你懂得我的固执 42 | [01:57.56]我懂你脾气 43 | [01:59.92]两颗心在靠近 44 | [02:02.68]等不及解释我的心情 45 | [02:06.54]怕错过爱上你的时机 46 | [02:11.05]浪漫已经 准备就绪 47 | [02:15.21]全新的旅行 48 | [02:20.12]多幸运 49 | [02:21.77]在最美的年纪 50 | [02:24.13]遇见你 51 | [02:26.19]没有遗憾和可惜 52 | [02:28.84]抱紧你 53 | [02:30.55]用尽全部力气 54 | [02:32.75]不让幸福逃离 55 | [02:37.57]多幸运 56 | [02:39.17]爱你这件事情 57 | [02:41.58]成为我 58 | [02:43.53]今生最对的决定 59 | [02:46.29]我相信 60 | [02:47.84]你就是那唯一 61 | [02:50.26]愿陪你到底 62 | [02:55.37]多幸运 遇见了你 63 | [02:58.43]多幸运 爱上了你 64 | [03:00.63]多幸运 能在一起 65 | [03:02.79]多幸运 遇见了你 66 | [03:06.91]多幸运 爱上了你 67 | [03:09.36]多幸运 能在一起 68 | [03:13.52]多幸运 69 | [03:14.48]在最美的年纪 70 | [03:16.43]遇见你 71 | [03:18.49]没有遗憾和可惜 72 | [03:20.85]抱紧你 73 | [03:22.75]用尽全部力气 74 | [03:24.86]不让幸福逃离 75 | [03:28.42]多幸运 76 | [03:31.43]爱你这件事情 77 | [03:33.78]成为我 78 | [03:35.89]今生最对的决定 79 | [03:38.29]我相信 80 | [03:40.20]你就是那唯一 81 | [03:42.68]愿陪你到底 82 | [03:47.04]这首歌送给我的唯一:Doris,i 💗 you 🌹 83 | -------------------------------------------------------------------------------- /lyricsAnalysis/父亲.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/lyricsAnalysis/父亲.mp3 -------------------------------------------------------------------------------- /lyricsAnalysis/父亲.txt: -------------------------------------------------------------------------------- 1 | 2 | [00:00.00]父亲 3 | [00:03.19]词曲:筷子兄弟 4 | [00:04.58]演唱:筷子兄弟 5 | [00:07.10] 6 | [00:26.31]总是向你索取 却不曾说谢谢你 7 | [00:32.21]直到长大以后 才懂得你不容易 8 | [00:39.11]每次离开总是 装做轻松的样子 9 | [00:45.32]微笑着说回去吧 转身泪湿眼底 10 | [00:52.10]多想和从前一样 牵你温暖手掌 11 | [00:58.47]可是你不在我身旁 托清风捎去安康 12 | [01:07.52] 13 | [01:08.71]时光时光慢些吧 不要再让你再变老了 14 | [01:15.29]我愿用我一切 换你岁月长留 15 | [01:21.07]一生要强的爸爸 我能为你做些什么 16 | [01:28.48]微不足道的关心收下吧 17 | [01:32.89] 18 | [01:35.06]谢谢你做的一切 双手撑起我们的家 19 | [01:41.41]总是竭尽所有 把最好的给我 20 | [01:47.27]我是你的骄傲吗 还在为我而担心吗 21 | [01:54.77]你牵挂的孩子啊 长大啦~~~~~ 22 | [01:59.58] 23 | [02:34.30]多想和从前一样 牵你温暖手掌 24 | [02:40.32]可是你不在我身旁 托清风捎去安康 25 | [02:48.51] 26 | [02:50.56]时光时光慢些吧 不要再让你再变老了 27 | [02:57.10]我愿用我一切 换你岁月长留 28 | [03:03.14]一生要强的爸爸 我能为你做些什么 29 | [03:10.36]微不足道的关心收下吧 30 | [03:14.77] 31 | [03:17.13]谢谢你做的一切 双手撑起我们的家 32 | [03:23.44]总是竭尽所有 把最好的给我 33 | [03:29.70]我是你的骄傲吗 还在为我而担心吗 34 | [03:36.42]你牵挂的孩子啊 长大啦~~~~~ 35 | [03:41.79] 36 | [03:43.03]时光时光慢些吧 不要再让你再变老了 37 | [03:49.82]我愿用我一切 换你岁月长留 38 | [03:56.37]我是你的骄傲吗 还在为我而担心吗 39 | [04:02.81]你牵挂的孩子啊 长大啦~~~~~ 40 | [04:07.79] 41 | [04:09.40]感谢一路上有你 42 | [04:13.00] 43 | -------------------------------------------------------------------------------- /lyricsAnalysisTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /lyricsAnalysisTests/lyricsAnalysisTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // lyricsAnalysisTests.m 3 | // lyricsAnalysisTests 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 王双龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface lyricsAnalysisTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation lyricsAnalysisTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /lyricsAnalysisUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /lyricsAnalysisUITests/lyricsAnalysisUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // lyricsAnalysisUITests.m 3 | // lyricsAnalysisUITests 4 | // 5 | // Created by 王双龙 on 2017/6/5. 6 | // Copyright © 2017年 王双龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface lyricsAnalysisUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation lyricsAnalysisUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /总效果.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsl2ls/LyricsAnalysis/1c78cca8b09da226b5bce2aa68095ce50a03f960/总效果.gif --------------------------------------------------------------------------------