From 6fa70af536dcdabd9688f50f65eec7d94095e89b Mon Sep 17 00:00:00 2001 From: kevinzhow Date: Fri, 3 Apr 2015 14:53:41 +0800 Subject: [PATCH] Refine Wave Compress --- Yep.xcodeproj/project.pbxproj | 12 +- .../ConversationViewController.swift | 14 +-- Yep/Views/AudioWaves/SampleView.swift | 5 +- Yep/Views/AudioWaves/SquareWaveView.swift | 92 ---------------- Yep/{Views/AudioWaves => }/Waver.swift | 103 +++++++++++++++++- 5 files changed, 113 insertions(+), 113 deletions(-) delete mode 100644 Yep/Views/AudioWaves/SquareWaveView.swift rename Yep/{Views/AudioWaves => }/Waver.swift (61%) diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index 4e241073..4f6b6d1d 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 0A8F54C71AB67D11004AD60E /* YepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8F54C61AB67D11004AD60E /* YepTests.swift */; }; 0A944C251AC8BB2F00037A06 /* YepStorageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A944C241AC8BB2F00037A06 /* YepStorageService.swift */; }; 0AAFCFF91AC8CA5B00EB0EF8 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AAFCFF81AC8CA5B00EB0EF8 /* MobileCoreServices.framework */; }; + 0ABF3EA71ACE60D5001E76ED /* Waver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABF3EA51ACE60D5001E76ED /* Waver.swift */; }; 0AD7EA5E1AC3ED1200617758 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA5D1AC3ED1200617758 /* CFNetwork.framework */; }; 0AD7EA601AC3ED1900617758 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA5F1AC3ED1900617758 /* CoreFoundation.framework */; }; 0AD7EA621AC3ED2100617758 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA611AC3ED2100617758 /* CoreTelephony.framework */; }; @@ -87,8 +88,6 @@ 50A9D44B1ACD37A8000B2599 /* NSFileManager+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A9D44A1ACD37A8000B2599 /* NSFileManager+Yep.swift */; }; 50A9D44E1ACD382B000B2599 /* NSDateTimeAgo.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 50A9D44C1ACD382B000B2599 /* NSDateTimeAgo.bundle */; }; 50A9D4511ACD383E000B2599 /* NSDate+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A9D4501ACD383E000B2599 /* NSDate+Extension.swift */; }; - 50A9D4551ACD393A000B2599 /* SquareWaveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A9D4521ACD393A000B2599 /* SquareWaveView.swift */; }; - 50A9D4561ACD393A000B2599 /* Waver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A9D4531ACD393A000B2599 /* Waver.swift */; }; 50A9D4571ACD393A000B2599 /* YepWaverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A9D4541ACD393A000B2599 /* YepWaverView.swift */; }; 50CDBE421ACA9B4200459CE0 /* ChatRightImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CDBE401ACA9B4200459CE0 /* ChatRightImageCell.swift */; }; 50CDBE431ACA9B4200459CE0 /* ChatRightImageCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50CDBE411ACA9B4200459CE0 /* ChatRightImageCell.xib */; }; @@ -130,6 +129,7 @@ 0A8F54C61AB67D11004AD60E /* YepTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YepTests.swift; sourceTree = ""; }; 0A944C241AC8BB2F00037A06 /* YepStorageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepStorageService.swift; path = Services/YepStorageService.swift; sourceTree = ""; }; 0AAFCFF81AC8CA5B00EB0EF8 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + 0ABF3EA51ACE60D5001E76ED /* Waver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Waver.swift; sourceTree = ""; }; 0AD7EA511AC3EA6F00617758 /* JPushSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JPushSDK.framework; path = "Pods/../build/Debug-iphoneos/Pods/JPushSDK.framework"; sourceTree = ""; }; 0AD7EA581AC3EAF300617758 /* Yep-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yep-Bridging-Header.h"; sourceTree = ""; }; 0AD7EA5B1AC3ECD700617758 /* libPushSDK-1.8.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPushSDK-1.8.3.a"; path = "Yep/lib/libPushSDK-1.8.3.a"; sourceTree = ""; }; @@ -201,8 +201,6 @@ 50A9D44A1ACD37A8000B2599 /* NSFileManager+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSFileManager+Yep.swift"; path = "Extensions/NSFileManager+Yep.swift"; sourceTree = ""; }; 50A9D44C1ACD382B000B2599 /* NSDateTimeAgo.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = NSDateTimeAgo.bundle; path = Extensions/NSDateTimeAgo.bundle; sourceTree = ""; }; 50A9D4501ACD383E000B2599 /* NSDate+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSDate+Extension.swift"; path = "Extensions/NSDate+Extension.swift"; sourceTree = ""; }; - 50A9D4521ACD393A000B2599 /* SquareWaveView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SquareWaveView.swift; path = Views/AudioWaves/SquareWaveView.swift; sourceTree = ""; }; - 50A9D4531ACD393A000B2599 /* Waver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Waver.swift; path = Views/AudioWaves/Waver.swift; sourceTree = ""; }; 50A9D4541ACD393A000B2599 /* YepWaverView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepWaverView.swift; path = Views/AudioWaves/YepWaverView.swift; sourceTree = ""; }; 50CDBE401ACA9B4200459CE0 /* ChatRightImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatRightImageCell.swift; path = Views/Cells/ChatRightImage/ChatRightImageCell.swift; sourceTree = ""; }; 50CDBE411ACA9B4200459CE0 /* ChatRightImageCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatRightImageCell.xib; path = Views/Cells/ChatRightImage/ChatRightImageCell.xib; sourceTree = ""; }; @@ -660,9 +658,8 @@ 50A9D4581ACD3943000B2599 /* AudioWaves */ = { isa = PBXGroup; children = ( - 50A9D4521ACD393A000B2599 /* SquareWaveView.swift */, + 0ABF3EA51ACE60D5001E76ED /* Waver.swift */, 504F41241ACE2D1D00FBB19A /* SampleView.swift */, - 50A9D4531ACD393A000B2599 /* Waver.swift */, 50A9D4541ACD393A000B2599 /* YepWaverView.swift */, ); name = AudioWaves; @@ -922,14 +919,13 @@ buildActionMask = 2147483647; files = ( 50CDBE421ACA9B4200459CE0 /* ChatRightImageCell.swift in Sources */, - 50A9D4561ACD393A000B2599 /* Waver.swift in Sources */, 5099B9C41AB9510D002F940B /* RankView.swift in Sources */, 502AE5311AB85067005BD199 /* RegisterPickMobileViewController.swift in Sources */, 5099B9C91AB9A7CB002F940B /* CameraPreviewView.swift in Sources */, - 50A9D4551ACD393A000B2599 /* SquareWaveView.swift in Sources */, 502AE5581AB932D5005BD199 /* ProfileSectionHeaderReusableView.swift in Sources */, 502AE5211AB71C7E005BD199 /* BorderButton.swift in Sources */, 502AE54E1AB93175005BD199 /* ProfileHeaderCell.swift in Sources */, + 0ABF3EA71ACE60D5001E76ED /* Waver.swift in Sources */, 502AE5381AB866E3005BD199 /* LoginVerifyMobileViewController.swift in Sources */, 503CAB431AC00CB100DFE830 /* ConversationViewController.swift in Sources */, 5023DE331AB688F600B3EE96 /* UIColor+Yep.swift in Sources */, diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 7e72d116..d87a1ce0 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -15,7 +15,6 @@ class ConversationViewController: UIViewController { var conversation: Conversation! var waverView: YepWaverView! - var audioSamples = [Float]() var samplesCount = 0 let samplingInterval = 6 @@ -178,10 +177,6 @@ class ConversationViewController: UIViewController { var normalizedValue = pow(10, audioRecorder.averagePowerForChannel(0)/40) - if (++self.samplesCount % self.samplingInterval) == 0 { - self.audioSamples.append(normalizedValue) - } - self.waverView.waver.level = CGFloat(normalizedValue) } } @@ -206,7 +201,7 @@ class ConversationViewController: UIViewController { let audioFileName = NSUUID().UUIDString - self.audioSamples.removeAll(keepCapacity: true) + self.waverView.waver.resetWaveSamples() self.samplesCount = 0 if let fileURL = NSFileManager.yepMessageAudioURLWithName(audioFileName) { @@ -228,13 +223,15 @@ class ConversationViewController: UIViewController { var metaData: String? = nil - let audioSamples = self.audioSamples + let audioSamples = self.waverView.waver.compressSamples() if let fileURL = YepAudioService.sharedManager.audioFileURL { let audioAsset = AVURLAsset(URL: fileURL, options: nil) let audioDuration = CMTimeGetSeconds(audioAsset.duration) as Double - let audioMetaDataInfo = ["audio_samples": audioSamples, "audio_duration": audioDuration] + println("Comporessed \(audioSamples)") + + let audioMetaDataInfo = ["audio_samples": audioSamples!, "audio_duration": audioDuration] if let audioMetaData = NSJSONSerialization.dataWithJSONObject(audioMetaDataInfo, options: nil, error: nil) { let audioMetaDataString = NSString(data: audioMetaData, encoding: NSUTF8StringEncoding) as? String @@ -669,6 +666,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let metaDataDict = decodeJSON(data) { if let audioSamples = metaDataDict["audio_samples"] as? [CGFloat] { + // cell.sampleViewWidthConstraint.constant = CGFloat(audioSamples.count) * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap()) - YepConfig.audioSampleGap() // 最后最后一个 gap 不要 cell.sampleView.samples = audioSamples diff --git a/Yep/Views/AudioWaves/SampleView.swift b/Yep/Views/AudioWaves/SampleView.swift index 2ccdfc66..239811b1 100644 --- a/Yep/Views/AudioWaves/SampleView.swift +++ b/Yep/Views/AudioWaves/SampleView.swift @@ -55,8 +55,11 @@ class SampleView: UIView { for (index, percent) in enumerate(samples) { let x = CGFloat(index) * sampleWidth + sampleGap * CGFloat(index) + let sampleHeightMax = viewHeight * 0.8 + let realSampleHeight = percent * viewHeight + - let sampleHeight = percent * (viewHeight * 0.9) + let sampleHeight = realSampleHeight < sampleHeightMax ? realSampleHeight: sampleHeightMax wavePath.moveToPoint(CGPointMake(x, viewHeight / 2.0 - sampleHeight / 2.0)) wavePath.addLineToPoint(CGPointMake(x, sampleHeight / 2.0 + viewHeight / 2.0)) diff --git a/Yep/Views/AudioWaves/SquareWaveView.swift b/Yep/Views/AudioWaves/SquareWaveView.swift deleted file mode 100644 index 2324fc98..00000000 --- a/Yep/Views/AudioWaves/SquareWaveView.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// SquareWaveView.swift -// Waver-Swift -// -// Created by kevinzhow on 15/4/1. -// Copyright (c) 2015年 kevinzhow. All rights reserved. -// - -import UIKit - -class SquareWaveView: UIView { - - var maxHeight: CGFloat = 1.0 - - var waves = [CGFloat]() - - var wave = CAShapeLayer() - - var waveWidth: CGFloat = 4.0 - - var waveGap: CGFloat = 1.0 - - var waveTotalCount: CGFloat! - - var waveSampleCount = 0 - - /* - // Only override drawRect: if you perform custom drawing. - // An empty implementation adversely affects performance during animation. - override func drawRect(rect: CGRect) { - // Drawing code - } - */ - - required init(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setup() - } - - override init(frame: CGRect) { - super.init(frame: frame) - setup() - } - - func setup() { - - wave.lineCap = kCALineCapButt - wave.lineJoin = kCALineJoinRound - wave.fillColor = UIColor.clearColor().CGColor - wave.lineWidth = waveWidth - wave.strokeColor = UIColor.grayColor().CGColor - self.layer.addSublayer(wave) - - waveTotalCount = self.bounds.width/(waveWidth+waveGap) - - } - - private func updateMeters() { - UIGraphicsBeginImageContext(self.frame.size) - - var wavesPath = UIBezierPath() - - for (index, wave) in enumerate(waves) { - - var x = CGFloat(index) * waveWidth + waveGap * CGFloat(index) - - wavesPath.moveToPoint(CGPointMake(x, self.bounds.height/2.0 - wave/2.0)) - wavesPath.addLineToPoint(CGPointMake(x, wave/2.0 + self.bounds.height/2.0)) - - } - - wave.path = wavesPath.CGPath - - UIGraphicsEndImageContext() - } - - func appendValue(newValue: CGFloat) { - - if ++waveSampleCount % 6 == 0{ - - waves.append(newValue*self.bounds.height) - - if waves.count > Int(waveTotalCount) { - waves.removeAtIndex(0) - } - - updateMeters() - } - - } - -} diff --git a/Yep/Views/AudioWaves/Waver.swift b/Yep/Waver.swift similarity index 61% rename from Yep/Views/AudioWaves/Waver.swift rename to Yep/Waver.swift index 5ad49a5e..fdcd25a7 100644 --- a/Yep/Views/AudioWaves/Waver.swift +++ b/Yep/Waver.swift @@ -20,6 +20,9 @@ class Waver: UIView { didSet { self.phase+=self.phaseShift; // Move the wave self.amplitude = fmax( level, self.idleAmplitude) + + self.appendValue(pow(CGFloat(level),3)) + self.updateMeters() } } @@ -42,10 +45,30 @@ class Waver: UIView { // - private var waveHeight: CGFloat! - private var waveWidth: CGFloat! - private var waveMid: CGFloat! - private var maxAmplitude: CGFloat! + var waveHeight: CGFloat! + var waveWidth: CGFloat! + var waveMid: CGFloat! + var maxAmplitude: CGFloat! + + // Sample Data + + var waveSampleCount = 0 + + var waveSamples = [CGFloat]() + + var waveTotalCount: CGFloat! + + var waveSquareWidth: CGFloat = 2.0 + + var waveGap: CGFloat = 1.0 + + var maxSquareWaveLength = 256 + + var maxTime = 60 + + var fps = 6 + + // var waverCallback: (() -> ())? { didSet { @@ -84,6 +107,16 @@ class Waver: UIView { setup() } + func appendValue(newValue: CGFloat) { + + if ++waveSampleCount % fps == 0{ + + waveSamples.append(newValue*5) + + updateMeters() + } + } + private func setup() { self.waveHeight = CGRectGetHeight(self.bounds) * 0.9 @@ -137,6 +170,68 @@ class Waver: UIView { UIGraphicsEndImageContext() } + func compressSamples() -> [Float]? { + + println("Begin compress") + + var finalSamples = [Float]() + + var samplesCount = waveSamples.count //获取总的 Sample 数量 + + var totalTime:CGFloat = CGFloat(waveSamples.count/(60/fps)) // 计算音频的时长 + + var bubbleWidth = -0.071*(totalTime*totalTime) + 8.532*totalTime //计算这个时长下的Bubble宽度,Bubble 的宽度和时间的关系函数是一个一元二次函数 + + var effectiveSample = bubbleWidth/(waveSquareWidth+waveGap) < 1 ? 1 : bubbleWidth/(waveSquareWidth+waveGap) //计算这个长度里实际可以放多少个sample图形 + if (effectiveSample > 10) { + + } + + var sampleGap = Int(CGFloat(samplesCount)/effectiveSample) //计算按照实际可放的sample数量,原sample需要每几个合并一次 + + var timePerSample = totalTime/(CGFloat(samplesCount)/effectiveSample) //计算合并后每个 sample 需要经过多少时间播放 + + + + println("samplesCount \(samplesCount) totalTime \(totalTime) bubbleWidth \(bubbleWidth) effectiveSample\(effectiveSample) sampleGap \(sampleGap) timePerSample\(timePerSample)") + + // + + var sampleCount = 0 + + var lastSample: CGFloat = 0 + + for sample in waveSamples { + + if ++sampleCount > sampleGap { + sampleCount = 0 + finalSamples.append(Float(lastSample)) + lastSample = 0 + }else{ + if (sample > lastSample) { + lastSample = sample + } + } + } + + if (finalSamples.count < 10){ + + finalSamples = [Float]() + + for sample in waveSamples { + finalSamples.append(Float(sample)) + } + } + + println("Final Sample is \(finalSamples)") + + return finalSamples + } + + func resetWaveSamples() { + waveSamples = [CGFloat]() + } + /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation.