├── .gitignore ├── .travis.yml ├── Example ├── Podfile ├── Tests │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── VOXHistogramLevelsConverterTests.m │ └── en.lproj │ │ └── InfoPlist.strings ├── VOXHistogramView.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── VOXHistogramView-Example.xcscheme └── VOXHistogramView │ ├── Helpers │ ├── VOXJSONConverter.h │ ├── VOXJSONConverter.m │ ├── VOXPlayerWrapper.h │ └── VOXPlayerWrapper.m │ ├── LaunchScreen.xib │ ├── Main.storyboard │ ├── Resources │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── levels.json │ └── pink20silence20.mp3 │ ├── VOXAppDelegate.h │ ├── VOXAppDelegate.m │ ├── VOXHistogramView-Info.plist │ ├── VOXHistogramView-Prefix.pch │ ├── ViewControllers │ ├── VOXControlHistogramViewController.h │ ├── VOXControlHistogramViewController.m │ ├── VOXSimpleHistogramViewController.h │ ├── VOXSimpleHistogramViewController.m │ ├── VOXTableViewController.h │ └── VOXTableViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── Gif └── demo.gif ├── LICENSE ├── Pod ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Animator │ ├── VOXHistogramAnimator.h │ └── VOXHistogramAnimator.m │ ├── Categories │ ├── UIView+Autolayout.h │ └── UIView+Autolayout.m │ ├── Configurations │ ├── VOXHistogramRenderingConfiguration.h │ └── VOXHistogramRenderingConfiguration.m │ ├── LevelsConverter │ ├── VOXHistogramLevelsConverter.h │ └── VOXHistogramLevelsConverter.m │ ├── ProgressLine │ ├── VOXProgressLineView.h │ └── VOXProgressLineView.m │ ├── Rendering │ ├── VOXHistogramRenderer.h │ ├── VOXHistogramRenderer.m │ ├── VOXHistogramRenderingOperation.h │ └── VOXHistogramRenderingOperation.m │ ├── VOXHistogramControlView.h │ ├── VOXHistogramControlView.m │ ├── VOXHistogramView.h │ └── VOXHistogramView.m ├── README.md ├── VOXHistogramView.podspec └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | *.xcworkspace 20 | .DS_Store 21 | .idea/ 22 | 23 | #CocoaPods 24 | Pods 25 | Podfile.lock 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | before_install: 3 | - brew install xctool 4 | - export LANG=en_US.UTF-8 5 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 6 | - gem install cocoapods 7 | - cd Example 8 | - pod install 9 | script: 10 | - xctool test -workspace VOXHistogramView.xcworkspace -scheme VOXHistogramView-Example -sdk iphonesimulator 11 | ONLY_ACTIVE_ARCH=NO 12 | notifications: 13 | email: 14 | recipients: 15 | - hawk.ukr@gmail.com 16 | on_success: change 17 | on_failure: always 18 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.1' 2 | 3 | source 'https://github.com/CocoaPods/Specs.git' 4 | 5 | inhibit_all_warnings! 6 | #use_frameworks! 7 | 8 | target 'VOXHistogramView_Example', :exclusive => true do 9 | pod "VOXHistogramView", :path => "../" 10 | pod 'APAudioPlayer' 11 | pod 'macros_blocks' 12 | pod 'FrameAccessor' 13 | end 14 | 15 | target 'VOXHistogramView_Tests', :exclusive => true do 16 | pod "VOXHistogramView", :path => "../" 17 | pod 'Expecta' 18 | pod 'OCMock' 19 | end 20 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/VOXHistogramLevelsConverterTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 3 | // 4 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 5 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 6 | // Contact phone: +1 (888) 765-7069 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "VOXHistogramLevelsConverter.h" 28 | #import "Expecta.h" 29 | 30 | 31 | @interface VOXHistogramLevelsConverterTests : XCTestCase 32 | 33 | 34 | #pragma mark - SUT 35 | @property(nonatomic, strong) VOXHistogramLevelsConverter *converter; 36 | @end 37 | 38 | 39 | 40 | @implementation VOXHistogramLevelsConverterTests 41 | 42 | 43 | - (void)setUp 44 | { 45 | [super setUp]; 46 | 47 | self.converter = [VOXHistogramLevelsConverter new]; 48 | 49 | NSArray *levels = [self buildLevelsForTesting]; 50 | [self.converter updateLevels:levels]; 51 | } 52 | 53 | - (void)tearDown 54 | { 55 | self.converter = nil; 56 | [super tearDown]; 57 | } 58 | 59 | #pragma mark - Update levels 60 | 61 | - (void)testUpdateLevels 62 | { 63 | expect(self.converter.levels).to.haveCountOf(15); 64 | 65 | [self.converter updateLevels:nil]; 66 | expect(self.converter.levels).to.beNil(); 67 | } 68 | 69 | #pragma mark - Calculate Levels 70 | 71 | - (void)testCalculateLevelsForSamplingRate_ShouldRaiseExceptionIfSamplingMoreThanLevelsCount 72 | { 73 | expect(^{ 74 | [self.converter calculateLevelsForSamplingRate:20 completion:nil]; 75 | }).to.raiseAny(); 76 | } 77 | 78 | - (void)testCalculateLevelsForSamplingRate_3_Samples 79 | { 80 | [self runAsyncCalculateLevelsForSamplingRate:3 withExpectationsBlock:^(NSArray *levels) { 81 | expect(levels).to.haveCountOf(3); 82 | expect(levels[0]).to.beCloseTo(@0.36666666666667); 83 | expect(levels[1]).to.equal(@0.0); 84 | expect(levels[2]).to.equal(@0.8); 85 | }]; 86 | } 87 | 88 | - (void)testCalculateLevelsForSamplingRate_5_Samples 89 | { 90 | [self runAsyncCalculateLevelsForSamplingRate:5 withExpectationsBlock:^(NSArray *levels) { 91 | expect(levels).to.haveCountOf(5); 92 | expect(levels[0]).to.beCloseTo(@0.43333333333333); 93 | expect(levels[1]).to.beCloseTo(@0.26666666666667); 94 | expect(levels[2]).to.equal(@0.0); 95 | expect(levels[3]).to.beCloseTo(@0.86666666666667); 96 | expect(levels[4]).to.beCloseTo(@0.56666666666667); 97 | }]; 98 | } 99 | 100 | - (void)testCalculateLevelsForSamplingRate_8_Samples 101 | { 102 | [self runAsyncCalculateLevelsForSamplingRate:8 withExpectationsBlock:^(NSArray *levels) { 103 | expect(levels).to.haveCountOf(8); 104 | expect(levels[0]).to.equal(@0.6); 105 | }]; 106 | } 107 | 108 | #pragma mark - Helpers 109 | 110 | - (void)runAsyncCalculateLevelsForSamplingRate:(NSUInteger)samplingRate withExpectationsBlock:(void (^)(NSArray *levels))expectationsBlock 111 | { 112 | XCTestExpectation *expectation = [self expectationWithDescription:nil]; 113 | [self.converter calculateLevelsForSamplingRate:samplingRate completion:^(NSArray *levels) { 114 | expectationsBlock(levels); 115 | [expectation fulfill]; 116 | }]; 117 | 118 | [self waitForExpectationsWithTimeout:3.0 handler:^(NSError *error) { 119 | if (error) { 120 | XCTFail(@"testCalculateLevelsForSamplingRate failed: %@", error); 121 | } 122 | }]; 123 | } 124 | 125 | - (NSArray *)buildLevelsForTesting 126 | { 127 | return @[ 128 | @0.5, @0.7, @0.1, @0.3, @0.5, 129 | @0.0, @0.0, @0.0, @0.0, @1.0, 130 | @0.8, @0.8, @0.8, @0.8, @0.1 131 | ]; 132 | } 133 | @end 134 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/VOXHistogramView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 11 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; 12 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 13 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; 14 | 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; }; 15 | 6003F59E195388D20070C39A /* VOXAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* VOXAppDelegate.m */; }; 16 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; 17 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 18 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 19 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; 20 | 71697E8D1B3ED39A00A7EB6E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 71697E8C1B3ED39A00A7EB6E /* LaunchScreen.xib */; }; 21 | 71FB0FDD1B3EC2D40034461C /* VOXJSONConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 71FB0FCE1B3EC2D40034461C /* VOXJSONConverter.m */; }; 22 | 71FB0FDE1B3EC2D40034461C /* VOXPlayerWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 71FB0FD01B3EC2D40034461C /* VOXPlayerWrapper.m */; }; 23 | 71FB0FDF1B3EC2D40034461C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 71FB0FD21B3EC2D40034461C /* Images.xcassets */; }; 24 | 71FB0FE01B3EC2D40034461C /* levels.json in Resources */ = {isa = PBXBuildFile; fileRef = 71FB0FD31B3EC2D40034461C /* levels.json */; }; 25 | 71FB0FE11B3EC2D40034461C /* pink20silence20.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 71FB0FD41B3EC2D40034461C /* pink20silence20.mp3 */; }; 26 | 71FB0FE21B3EC2D40034461C /* VOXControlHistogramViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71FB0FD71B3EC2D40034461C /* VOXControlHistogramViewController.m */; }; 27 | 71FB0FE31B3EC2D40034461C /* VOXSimpleHistogramViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71FB0FD91B3EC2D40034461C /* VOXSimpleHistogramViewController.m */; }; 28 | 71FB0FE41B3EC2D40034461C /* VOXTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71FB0FDB1B3EC2D40034461C /* VOXTableViewController.m */; }; 29 | 71FB0FE61B3EC3820034461C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71FB0FE51B3EC3820034461C /* Main.storyboard */; }; 30 | 8A66A2DED9E15CD279668F3F /* libPods-VOXHistogramView_Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 94E7E76625358F6D7325A7D7 /* libPods-VOXHistogramView_Tests.a */; }; 31 | B65537312F6A0C928EB5209C /* VOXHistogramLevelsConverterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B655328032E130111FDADB72 /* VOXHistogramLevelsConverterTests.m */; }; 32 | D6BDD3282FB05B2F15221A59 /* libPods-VOXHistogramView_Example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AC04319ED8CB0971952728EB /* libPods-VOXHistogramView_Example.a */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 6003F582195388D10070C39A /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 6003F589195388D20070C39A; 41 | remoteInfo = VOXHistogramView; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 01213C494C6660BCE86E1EC1 /* Pods-VOXHistogramView_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VOXHistogramView_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VOXHistogramView_Tests/Pods-VOXHistogramView_Tests.debug.xcconfig"; sourceTree = ""; }; 47 | 0E44244D22C6636AD5F992F4 /* Pods-VOXHistogramView_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VOXHistogramView_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VOXHistogramView_Example/Pods-VOXHistogramView_Example.debug.xcconfig"; sourceTree = ""; }; 48 | 102F05100418733F2372E3E8 /* Pods-VOXHistogramView_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VOXHistogramView_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-VOXHistogramView_Example/Pods-VOXHistogramView_Example.release.xcconfig"; sourceTree = ""; }; 49 | 1251BD4B2C95038EE0689182 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 50 | 2BD9DA32433F31C658014600 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 51 | 31A0AA72121C062F8D8B520C /* VOXHistogramView.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = VOXHistogramView.podspec; path = ../VOXHistogramView.podspec; sourceTree = ""; }; 52 | 6003F58A195388D20070C39A /* VOXHistogramView_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VOXHistogramView_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 54 | 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 55 | 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 56 | 6003F595195388D20070C39A /* VOXHistogramView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "VOXHistogramView-Info.plist"; sourceTree = ""; }; 57 | 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | 6003F59B195388D20070C39A /* VOXHistogramView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "VOXHistogramView-Prefix.pch"; sourceTree = ""; }; 60 | 6003F59C195388D20070C39A /* VOXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VOXAppDelegate.h; sourceTree = ""; }; 61 | 6003F59D195388D20070C39A /* VOXAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VOXAppDelegate.m; sourceTree = ""; }; 62 | 6003F5AE195388D20070C39A /* VOXHistogramView_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VOXHistogramView_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 64 | 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 65 | 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 66 | 6004BC293FA95C142DA4FEB6 /* Pods-VOXHistogramView_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VOXHistogramView_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-VOXHistogramView_Tests/Pods-VOXHistogramView_Tests.release.xcconfig"; sourceTree = ""; }; 67 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = ""; }; 68 | 71697E8C1B3ED39A00A7EB6E /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; 69 | 71FB0FCD1B3EC2D40034461C /* VOXJSONConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VOXJSONConverter.h; sourceTree = ""; }; 70 | 71FB0FCE1B3EC2D40034461C /* VOXJSONConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXJSONConverter.m; sourceTree = ""; }; 71 | 71FB0FCF1B3EC2D40034461C /* VOXPlayerWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VOXPlayerWrapper.h; sourceTree = ""; }; 72 | 71FB0FD01B3EC2D40034461C /* VOXPlayerWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXPlayerWrapper.m; sourceTree = ""; }; 73 | 71FB0FD21B3EC2D40034461C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 74 | 71FB0FD31B3EC2D40034461C /* levels.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = levels.json; sourceTree = ""; }; 75 | 71FB0FD41B3EC2D40034461C /* pink20silence20.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = pink20silence20.mp3; sourceTree = ""; }; 76 | 71FB0FD61B3EC2D40034461C /* VOXControlHistogramViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VOXControlHistogramViewController.h; sourceTree = ""; }; 77 | 71FB0FD71B3EC2D40034461C /* VOXControlHistogramViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXControlHistogramViewController.m; sourceTree = ""; }; 78 | 71FB0FD81B3EC2D40034461C /* VOXSimpleHistogramViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VOXSimpleHistogramViewController.h; sourceTree = ""; }; 79 | 71FB0FD91B3EC2D40034461C /* VOXSimpleHistogramViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXSimpleHistogramViewController.m; sourceTree = ""; }; 80 | 71FB0FDA1B3EC2D40034461C /* VOXTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VOXTableViewController.h; sourceTree = ""; }; 81 | 71FB0FDB1B3EC2D40034461C /* VOXTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXTableViewController.m; sourceTree = ""; }; 82 | 71FB0FE51B3EC3820034461C /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 83 | 94E7E76625358F6D7325A7D7 /* libPods-VOXHistogramView_Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VOXHistogramView_Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | AC04319ED8CB0971952728EB /* libPods-VOXHistogramView_Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VOXHistogramView_Example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | B655328032E130111FDADB72 /* VOXHistogramLevelsConverterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VOXHistogramLevelsConverterTests.m; sourceTree = ""; }; 86 | /* End PBXFileReference section */ 87 | 88 | /* Begin PBXFrameworksBuildPhase section */ 89 | 6003F587195388D20070C39A /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, 94 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 95 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, 96 | D6BDD3282FB05B2F15221A59 /* libPods-VOXHistogramView_Example.a in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | 6003F5AB195388D20070C39A /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, 105 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 106 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 107 | 8A66A2DED9E15CD279668F3F /* libPods-VOXHistogramView_Tests.a in Frameworks */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXFrameworksBuildPhase section */ 112 | 113 | /* Begin PBXGroup section */ 114 | 59884C268B78AE84C894B56D /* Pods */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 0E44244D22C6636AD5F992F4 /* Pods-VOXHistogramView_Example.debug.xcconfig */, 118 | 102F05100418733F2372E3E8 /* Pods-VOXHistogramView_Example.release.xcconfig */, 119 | 01213C494C6660BCE86E1EC1 /* Pods-VOXHistogramView_Tests.debug.xcconfig */, 120 | 6004BC293FA95C142DA4FEB6 /* Pods-VOXHistogramView_Tests.release.xcconfig */, 121 | ); 122 | name = Pods; 123 | sourceTree = ""; 124 | }; 125 | 6003F581195388D10070C39A = { 126 | isa = PBXGroup; 127 | children = ( 128 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, 129 | 6003F593195388D20070C39A /* Example for VOXHistogramView */, 130 | 6003F5B5195388D20070C39A /* Tests */, 131 | 6003F58C195388D20070C39A /* Frameworks */, 132 | 6003F58B195388D20070C39A /* Products */, 133 | 59884C268B78AE84C894B56D /* Pods */, 134 | ); 135 | sourceTree = ""; 136 | }; 137 | 6003F58B195388D20070C39A /* Products */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 6003F58A195388D20070C39A /* VOXHistogramView_Example.app */, 141 | 6003F5AE195388D20070C39A /* VOXHistogramView_Tests.xctest */, 142 | ); 143 | name = Products; 144 | sourceTree = ""; 145 | }; 146 | 6003F58C195388D20070C39A /* Frameworks */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 6003F58D195388D20070C39A /* Foundation.framework */, 150 | 6003F58F195388D20070C39A /* CoreGraphics.framework */, 151 | 6003F591195388D20070C39A /* UIKit.framework */, 152 | 6003F5AF195388D20070C39A /* XCTest.framework */, 153 | AC04319ED8CB0971952728EB /* libPods-VOXHistogramView_Example.a */, 154 | 94E7E76625358F6D7325A7D7 /* libPods-VOXHistogramView_Tests.a */, 155 | ); 156 | name = Frameworks; 157 | sourceTree = ""; 158 | }; 159 | 6003F593195388D20070C39A /* Example for VOXHistogramView */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 71FB0FCC1B3EC2D40034461C /* Helpers */, 163 | 71FB0FD11B3EC2D40034461C /* Resources */, 164 | 71FB0FD51B3EC2D40034461C /* ViewControllers */, 165 | 6003F594195388D20070C39A /* Supporting Files */, 166 | 71FB0FE51B3EC3820034461C /* Main.storyboard */, 167 | 71697E8C1B3ED39A00A7EB6E /* LaunchScreen.xib */, 168 | 6003F59C195388D20070C39A /* VOXAppDelegate.h */, 169 | 6003F59D195388D20070C39A /* VOXAppDelegate.m */, 170 | ); 171 | name = "Example for VOXHistogramView"; 172 | path = VOXHistogramView; 173 | sourceTree = ""; 174 | }; 175 | 6003F594195388D20070C39A /* Supporting Files */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 6003F595195388D20070C39A /* VOXHistogramView-Info.plist */, 179 | 6003F596195388D20070C39A /* InfoPlist.strings */, 180 | 6003F599195388D20070C39A /* main.m */, 181 | 6003F59B195388D20070C39A /* VOXHistogramView-Prefix.pch */, 182 | ); 183 | name = "Supporting Files"; 184 | sourceTree = ""; 185 | }; 186 | 6003F5B5195388D20070C39A /* Tests */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 6003F5B6195388D20070C39A /* Supporting Files */, 190 | B655328032E130111FDADB72 /* VOXHistogramLevelsConverterTests.m */, 191 | ); 192 | path = Tests; 193 | sourceTree = ""; 194 | }; 195 | 6003F5B6195388D20070C39A /* Supporting Files */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 6003F5B7195388D20070C39A /* Tests-Info.plist */, 199 | 6003F5B8195388D20070C39A /* InfoPlist.strings */, 200 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, 201 | ); 202 | name = "Supporting Files"; 203 | sourceTree = ""; 204 | }; 205 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | 31A0AA72121C062F8D8B520C /* VOXHistogramView.podspec */, 209 | 2BD9DA32433F31C658014600 /* README.md */, 210 | 1251BD4B2C95038EE0689182 /* LICENSE */, 211 | ); 212 | name = "Podspec Metadata"; 213 | sourceTree = ""; 214 | }; 215 | 71FB0FCC1B3EC2D40034461C /* Helpers */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | 71FB0FCD1B3EC2D40034461C /* VOXJSONConverter.h */, 219 | 71FB0FCE1B3EC2D40034461C /* VOXJSONConverter.m */, 220 | 71FB0FCF1B3EC2D40034461C /* VOXPlayerWrapper.h */, 221 | 71FB0FD01B3EC2D40034461C /* VOXPlayerWrapper.m */, 222 | ); 223 | path = Helpers; 224 | sourceTree = ""; 225 | }; 226 | 71FB0FD11B3EC2D40034461C /* Resources */ = { 227 | isa = PBXGroup; 228 | children = ( 229 | 71FB0FD21B3EC2D40034461C /* Images.xcassets */, 230 | 71FB0FD31B3EC2D40034461C /* levels.json */, 231 | 71FB0FD41B3EC2D40034461C /* pink20silence20.mp3 */, 232 | ); 233 | path = Resources; 234 | sourceTree = ""; 235 | }; 236 | 71FB0FD51B3EC2D40034461C /* ViewControllers */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | 71FB0FD61B3EC2D40034461C /* VOXControlHistogramViewController.h */, 240 | 71FB0FD71B3EC2D40034461C /* VOXControlHistogramViewController.m */, 241 | 71FB0FD81B3EC2D40034461C /* VOXSimpleHistogramViewController.h */, 242 | 71FB0FD91B3EC2D40034461C /* VOXSimpleHistogramViewController.m */, 243 | 71FB0FDA1B3EC2D40034461C /* VOXTableViewController.h */, 244 | 71FB0FDB1B3EC2D40034461C /* VOXTableViewController.m */, 245 | ); 246 | path = ViewControllers; 247 | sourceTree = ""; 248 | }; 249 | /* End PBXGroup section */ 250 | 251 | /* Begin PBXNativeTarget section */ 252 | 6003F589195388D20070C39A /* VOXHistogramView_Example */ = { 253 | isa = PBXNativeTarget; 254 | buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "VOXHistogramView_Example" */; 255 | buildPhases = ( 256 | 138C61765CA9ECE5A02AA85E /* Check Pods Manifest.lock */, 257 | 6003F586195388D20070C39A /* Sources */, 258 | 6003F587195388D20070C39A /* Frameworks */, 259 | 6003F588195388D20070C39A /* Resources */, 260 | 24EEDC0547604F48C3DADBB6 /* Copy Pods Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = VOXHistogramView_Example; 267 | productName = VOXHistogramView; 268 | productReference = 6003F58A195388D20070C39A /* VOXHistogramView_Example.app */; 269 | productType = "com.apple.product-type.application"; 270 | }; 271 | 6003F5AD195388D20070C39A /* VOXHistogramView_Tests */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "VOXHistogramView_Tests" */; 274 | buildPhases = ( 275 | EC09068E82E99B232C02F6AB /* Check Pods Manifest.lock */, 276 | 6003F5AA195388D20070C39A /* Sources */, 277 | 6003F5AB195388D20070C39A /* Frameworks */, 278 | 6003F5AC195388D20070C39A /* Resources */, 279 | 2CC4DB15140E50BBB7815131 /* Copy Pods Resources */, 280 | ); 281 | buildRules = ( 282 | ); 283 | dependencies = ( 284 | 6003F5B4195388D20070C39A /* PBXTargetDependency */, 285 | ); 286 | name = VOXHistogramView_Tests; 287 | productName = VOXHistogramViewTests; 288 | productReference = 6003F5AE195388D20070C39A /* VOXHistogramView_Tests.xctest */; 289 | productType = "com.apple.product-type.bundle.unit-test"; 290 | }; 291 | /* End PBXNativeTarget section */ 292 | 293 | /* Begin PBXProject section */ 294 | 6003F582195388D10070C39A /* Project object */ = { 295 | isa = PBXProject; 296 | attributes = { 297 | CLASSPREFIX = VOX; 298 | LastUpgradeCheck = 0510; 299 | ORGANIZATIONNAME = "Nickolay Sheika"; 300 | TargetAttributes = { 301 | 6003F5AD195388D20070C39A = { 302 | TestTargetID = 6003F589195388D20070C39A; 303 | }; 304 | }; 305 | }; 306 | buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "VOXHistogramView" */; 307 | compatibilityVersion = "Xcode 3.2"; 308 | developmentRegion = English; 309 | hasScannedForEncodings = 0; 310 | knownRegions = ( 311 | en, 312 | Base, 313 | ); 314 | mainGroup = 6003F581195388D10070C39A; 315 | productRefGroup = 6003F58B195388D20070C39A /* Products */; 316 | projectDirPath = ""; 317 | projectRoot = ""; 318 | targets = ( 319 | 6003F589195388D20070C39A /* VOXHistogramView_Example */, 320 | 6003F5AD195388D20070C39A /* VOXHistogramView_Tests */, 321 | ); 322 | }; 323 | /* End PBXProject section */ 324 | 325 | /* Begin PBXResourcesBuildPhase section */ 326 | 6003F588195388D20070C39A /* Resources */ = { 327 | isa = PBXResourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | 71FB0FE01B3EC2D40034461C /* levels.json in Resources */, 331 | 71FB0FDF1B3EC2D40034461C /* Images.xcassets in Resources */, 332 | 71FB0FE61B3EC3820034461C /* Main.storyboard in Resources */, 333 | 71FB0FE11B3EC2D40034461C /* pink20silence20.mp3 in Resources */, 334 | 71697E8D1B3ED39A00A7EB6E /* LaunchScreen.xib in Resources */, 335 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | 6003F5AC195388D20070C39A /* Resources */ = { 340 | isa = PBXResourcesBuildPhase; 341 | buildActionMask = 2147483647; 342 | files = ( 343 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXResourcesBuildPhase section */ 348 | 349 | /* Begin PBXShellScriptBuildPhase section */ 350 | 138C61765CA9ECE5A02AA85E /* Check Pods Manifest.lock */ = { 351 | isa = PBXShellScriptBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | ); 355 | inputPaths = ( 356 | ); 357 | name = "Check Pods Manifest.lock"; 358 | outputPaths = ( 359 | ); 360 | runOnlyForDeploymentPostprocessing = 0; 361 | shellPath = /bin/sh; 362 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 363 | showEnvVarsInLog = 0; 364 | }; 365 | 24EEDC0547604F48C3DADBB6 /* Copy Pods Resources */ = { 366 | isa = PBXShellScriptBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | ); 370 | inputPaths = ( 371 | ); 372 | name = "Copy Pods Resources"; 373 | outputPaths = ( 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | shellPath = /bin/sh; 377 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-VOXHistogramView_Example/Pods-VOXHistogramView_Example-resources.sh\"\n"; 378 | showEnvVarsInLog = 0; 379 | }; 380 | 2CC4DB15140E50BBB7815131 /* Copy Pods Resources */ = { 381 | isa = PBXShellScriptBuildPhase; 382 | buildActionMask = 2147483647; 383 | files = ( 384 | ); 385 | inputPaths = ( 386 | ); 387 | name = "Copy Pods Resources"; 388 | outputPaths = ( 389 | ); 390 | runOnlyForDeploymentPostprocessing = 0; 391 | shellPath = /bin/sh; 392 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-VOXHistogramView_Tests/Pods-VOXHistogramView_Tests-resources.sh\"\n"; 393 | showEnvVarsInLog = 0; 394 | }; 395 | EC09068E82E99B232C02F6AB /* Check Pods Manifest.lock */ = { 396 | isa = PBXShellScriptBuildPhase; 397 | buildActionMask = 2147483647; 398 | files = ( 399 | ); 400 | inputPaths = ( 401 | ); 402 | name = "Check Pods Manifest.lock"; 403 | outputPaths = ( 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | shellPath = /bin/sh; 407 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 408 | showEnvVarsInLog = 0; 409 | }; 410 | /* End PBXShellScriptBuildPhase section */ 411 | 412 | /* Begin PBXSourcesBuildPhase section */ 413 | 6003F586195388D20070C39A /* Sources */ = { 414 | isa = PBXSourcesBuildPhase; 415 | buildActionMask = 2147483647; 416 | files = ( 417 | 71FB0FDE1B3EC2D40034461C /* VOXPlayerWrapper.m in Sources */, 418 | 71FB0FDD1B3EC2D40034461C /* VOXJSONConverter.m in Sources */, 419 | 6003F59E195388D20070C39A /* VOXAppDelegate.m in Sources */, 420 | 71FB0FE41B3EC2D40034461C /* VOXTableViewController.m in Sources */, 421 | 71FB0FE31B3EC2D40034461C /* VOXSimpleHistogramViewController.m in Sources */, 422 | 6003F59A195388D20070C39A /* main.m in Sources */, 423 | 71FB0FE21B3EC2D40034461C /* VOXControlHistogramViewController.m in Sources */, 424 | ); 425 | runOnlyForDeploymentPostprocessing = 0; 426 | }; 427 | 6003F5AA195388D20070C39A /* Sources */ = { 428 | isa = PBXSourcesBuildPhase; 429 | buildActionMask = 2147483647; 430 | files = ( 431 | B65537312F6A0C928EB5209C /* VOXHistogramLevelsConverterTests.m in Sources */, 432 | ); 433 | runOnlyForDeploymentPostprocessing = 0; 434 | }; 435 | /* End PBXSourcesBuildPhase section */ 436 | 437 | /* Begin PBXTargetDependency section */ 438 | 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { 439 | isa = PBXTargetDependency; 440 | target = 6003F589195388D20070C39A /* VOXHistogramView_Example */; 441 | targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; 442 | }; 443 | /* End PBXTargetDependency section */ 444 | 445 | /* Begin PBXVariantGroup section */ 446 | 6003F596195388D20070C39A /* InfoPlist.strings */ = { 447 | isa = PBXVariantGroup; 448 | children = ( 449 | 6003F597195388D20070C39A /* en */, 450 | ); 451 | name = InfoPlist.strings; 452 | sourceTree = ""; 453 | }; 454 | 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { 455 | isa = PBXVariantGroup; 456 | children = ( 457 | 6003F5B9195388D20070C39A /* en */, 458 | ); 459 | name = InfoPlist.strings; 460 | sourceTree = ""; 461 | }; 462 | /* End PBXVariantGroup section */ 463 | 464 | /* Begin XCBuildConfiguration section */ 465 | 6003F5BD195388D20070C39A /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ALWAYS_SEARCH_USER_PATHS = NO; 469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 470 | CLANG_CXX_LIBRARY = "libc++"; 471 | CLANG_ENABLE_MODULES = YES; 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | CLANG_WARN_BOOL_CONVERSION = YES; 474 | CLANG_WARN_CONSTANT_CONVERSION = YES; 475 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 476 | CLANG_WARN_EMPTY_BODY = YES; 477 | CLANG_WARN_ENUM_CONVERSION = YES; 478 | CLANG_WARN_INT_CONVERSION = YES; 479 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 480 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 481 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 482 | COPY_PHASE_STRIP = NO; 483 | GCC_C_LANGUAGE_STANDARD = gnu99; 484 | GCC_DYNAMIC_NO_PIC = NO; 485 | GCC_OPTIMIZATION_LEVEL = 0; 486 | GCC_PREPROCESSOR_DEFINITIONS = ( 487 | "DEBUG=1", 488 | "$(inherited)", 489 | ); 490 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 491 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 492 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 493 | GCC_WARN_UNDECLARED_SELECTOR = YES; 494 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 495 | GCC_WARN_UNUSED_FUNCTION = YES; 496 | GCC_WARN_UNUSED_VARIABLE = YES; 497 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 498 | ONLY_ACTIVE_ARCH = YES; 499 | SDKROOT = iphoneos; 500 | TARGETED_DEVICE_FAMILY = "1,2"; 501 | }; 502 | name = Debug; 503 | }; 504 | 6003F5BE195388D20070C39A /* Release */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | ALWAYS_SEARCH_USER_PATHS = NO; 508 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 509 | CLANG_CXX_LIBRARY = "libc++"; 510 | CLANG_ENABLE_MODULES = YES; 511 | CLANG_ENABLE_OBJC_ARC = YES; 512 | CLANG_WARN_BOOL_CONVERSION = YES; 513 | CLANG_WARN_CONSTANT_CONVERSION = YES; 514 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 515 | CLANG_WARN_EMPTY_BODY = YES; 516 | CLANG_WARN_ENUM_CONVERSION = YES; 517 | CLANG_WARN_INT_CONVERSION = YES; 518 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 519 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 520 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 521 | COPY_PHASE_STRIP = YES; 522 | ENABLE_NS_ASSERTIONS = NO; 523 | GCC_C_LANGUAGE_STANDARD = gnu99; 524 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 525 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 526 | GCC_WARN_UNDECLARED_SELECTOR = YES; 527 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 528 | GCC_WARN_UNUSED_FUNCTION = YES; 529 | GCC_WARN_UNUSED_VARIABLE = YES; 530 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 531 | SDKROOT = iphoneos; 532 | TARGETED_DEVICE_FAMILY = "1,2"; 533 | VALIDATE_PRODUCT = YES; 534 | }; 535 | name = Release; 536 | }; 537 | 6003F5C0195388D20070C39A /* Debug */ = { 538 | isa = XCBuildConfiguration; 539 | baseConfigurationReference = 0E44244D22C6636AD5F992F4 /* Pods-VOXHistogramView_Example.debug.xcconfig */; 540 | buildSettings = { 541 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 542 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 543 | GCC_PREFIX_HEADER = "VOXHistogramView/VOXHistogramView-Prefix.pch"; 544 | INFOPLIST_FILE = "VOXHistogramView/VOXHistogramView-Info.plist"; 545 | MODULE_NAME = ExampleApp; 546 | PRODUCT_NAME = "$(TARGET_NAME)"; 547 | WRAPPER_EXTENSION = app; 548 | }; 549 | name = Debug; 550 | }; 551 | 6003F5C1195388D20070C39A /* Release */ = { 552 | isa = XCBuildConfiguration; 553 | baseConfigurationReference = 102F05100418733F2372E3E8 /* Pods-VOXHistogramView_Example.release.xcconfig */; 554 | buildSettings = { 555 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 556 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 557 | GCC_PREFIX_HEADER = "VOXHistogramView/VOXHistogramView-Prefix.pch"; 558 | INFOPLIST_FILE = "VOXHistogramView/VOXHistogramView-Info.plist"; 559 | MODULE_NAME = ExampleApp; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | WRAPPER_EXTENSION = app; 562 | }; 563 | name = Release; 564 | }; 565 | 6003F5C3195388D20070C39A /* Debug */ = { 566 | isa = XCBuildConfiguration; 567 | baseConfigurationReference = 01213C494C6660BCE86E1EC1 /* Pods-VOXHistogramView_Tests.debug.xcconfig */; 568 | buildSettings = { 569 | BUNDLE_LOADER = "$(TEST_HOST)"; 570 | FRAMEWORK_SEARCH_PATHS = ( 571 | "$(SDKROOT)/Developer/Library/Frameworks", 572 | "$(inherited)", 573 | "$(DEVELOPER_FRAMEWORKS_DIR)", 574 | ); 575 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 576 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 577 | GCC_PREPROCESSOR_DEFINITIONS = ( 578 | "DEBUG=1", 579 | "$(inherited)", 580 | ); 581 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 582 | PRODUCT_NAME = "$(TARGET_NAME)"; 583 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VOXHistogramView_Example.app/VOXHistogramView_Example"; 584 | WRAPPER_EXTENSION = xctest; 585 | }; 586 | name = Debug; 587 | }; 588 | 6003F5C4195388D20070C39A /* Release */ = { 589 | isa = XCBuildConfiguration; 590 | baseConfigurationReference = 6004BC293FA95C142DA4FEB6 /* Pods-VOXHistogramView_Tests.release.xcconfig */; 591 | buildSettings = { 592 | BUNDLE_LOADER = "$(TEST_HOST)"; 593 | FRAMEWORK_SEARCH_PATHS = ( 594 | "$(SDKROOT)/Developer/Library/Frameworks", 595 | "$(inherited)", 596 | "$(DEVELOPER_FRAMEWORKS_DIR)", 597 | ); 598 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 599 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 600 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 601 | PRODUCT_NAME = "$(TARGET_NAME)"; 602 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VOXHistogramView_Example.app/VOXHistogramView_Example"; 603 | WRAPPER_EXTENSION = xctest; 604 | }; 605 | name = Release; 606 | }; 607 | /* End XCBuildConfiguration section */ 608 | 609 | /* Begin XCConfigurationList section */ 610 | 6003F585195388D10070C39A /* Build configuration list for PBXProject "VOXHistogramView" */ = { 611 | isa = XCConfigurationList; 612 | buildConfigurations = ( 613 | 6003F5BD195388D20070C39A /* Debug */, 614 | 6003F5BE195388D20070C39A /* Release */, 615 | ); 616 | defaultConfigurationIsVisible = 0; 617 | defaultConfigurationName = Release; 618 | }; 619 | 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "VOXHistogramView_Example" */ = { 620 | isa = XCConfigurationList; 621 | buildConfigurations = ( 622 | 6003F5C0195388D20070C39A /* Debug */, 623 | 6003F5C1195388D20070C39A /* Release */, 624 | ); 625 | defaultConfigurationIsVisible = 0; 626 | defaultConfigurationName = Release; 627 | }; 628 | 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "VOXHistogramView_Tests" */ = { 629 | isa = XCConfigurationList; 630 | buildConfigurations = ( 631 | 6003F5C3195388D20070C39A /* Debug */, 632 | 6003F5C4195388D20070C39A /* Release */, 633 | ); 634 | defaultConfigurationIsVisible = 0; 635 | defaultConfigurationName = Release; 636 | }; 637 | /* End XCConfigurationList section */ 638 | }; 639 | rootObject = 6003F582195388D10070C39A /* Project object */; 640 | } 641 | -------------------------------------------------------------------------------- /Example/VOXHistogramView.xcodeproj/xcshareddata/xcschemes/VOXHistogramView-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 28 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 46 | 52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 | 65 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/Helpers/VOXJSONConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/8/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | @interface VOXJSONConverter : NSObject 30 | 31 | /** 32 | * Reads data from local file and returns NSDictionary or NSArray object 33 | * 34 | * @param fileName filename with extension 35 | * 36 | * @return NSArray or NSDictionary 37 | */ 38 | + (id)jsonObjectWithFileName:(NSString *)fileName; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/Helpers/VOXJSONConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/8/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXJSONConverter.h" 28 | 29 | @implementation VOXJSONConverter 30 | 31 | + (id)jsonObjectWithFileName:(NSString *)fileName 32 | { 33 | NSBundle *bundle = [NSBundle bundleForClass:self]; 34 | NSString *path = [bundle pathForResource:fileName ofType:nil]; 35 | NSData *jsonData = [NSData dataWithContentsOfFile:path]; 36 | return [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:NULL]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/Helpers/VOXPlayerWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 26.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import 29 | 30 | @class VOXPlayerWrapper; 31 | 32 | 33 | 34 | @protocol VOXPlayerWrapperDelegate 35 | 36 | 37 | @optional 38 | - (void)playerDidPause:(VOXPlayerWrapper *)playerWrapper; 39 | - (void)playerDidStartPlaying:(VOXPlayerWrapper *)playerWrapper; 40 | - (void)playerDidFinishCurrentTrack:(VOXPlayerWrapper *)playerWrapper; 41 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 42 | downloadProgressChanged:(CGFloat)downloadProgress; 43 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 44 | playbackProgressChanged:(CGFloat)playbackProgress; 45 | 46 | 47 | @end 48 | 49 | 50 | 51 | @interface VOXPlayerWrapper : NSObject 52 | 53 | 54 | #pragma mark - Init 55 | - (instancetype)initWithPlayer:(APAudioPlayer *)player NS_DESIGNATED_INITIALIZER; 56 | + (instancetype)wrapperWithPlayer:(APAudioPlayer *)player; 57 | 58 | #pragma mark - Delegate 59 | @property(nonatomic, weak) id delegate; 60 | 61 | #pragma mark - Player 62 | - (void)startPlayingTrackWithURL:(NSURL *)url; 63 | - (BOOL)isPlaying; 64 | - (void)play; 65 | - (void)pause; 66 | @property(nonatomic, assign) CGFloat position; 67 | 68 | /* Clean up timers to avoid retain cycle */ 69 | - (void)cleanUp; 70 | @end 71 | 72 | 73 | 74 | @interface VOXPlayerWrapper (Unavailable) 75 | 76 | 77 | - (instancetype)init NS_UNAVAILABLE; 78 | + (instancetype)new NS_UNAVAILABLE; 79 | 80 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/Helpers/VOXPlayerWrapper.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 26.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "VOXPlayerWrapper.h" 29 | 30 | 31 | static NSUInteger const VOXDownloadTicksCount = 10; 32 | 33 | 34 | 35 | @interface VOXPlayerWrapper () 36 | 37 | 38 | #pragma mark - Player 39 | @property(nonatomic, strong) APAudioPlayer *player; 40 | 41 | #pragma mark - Helpers 42 | @property(nonatomic, strong) NSTimer *progressTimer; 43 | @property(nonatomic, strong) NSTimer *downloadTimer; 44 | @property(nonatomic, assign) NSUInteger downloadTicksCount; 45 | @property(nonatomic, assign) CGFloat downloadProgress; 46 | 47 | @end 48 | 49 | 50 | 51 | @implementation VOXPlayerWrapper 52 | 53 | 54 | #pragma mark - Accessors 55 | 56 | - (CGFloat)position 57 | { 58 | return self.player.position; 59 | } 60 | 61 | - (void)setPosition:(CGFloat)position 62 | { 63 | [self.player setPosition:position]; 64 | } 65 | 66 | #pragma mark - Init 67 | 68 | - (instancetype)initWithPlayer:(APAudioPlayer *)player 69 | { 70 | self = [super init]; 71 | if (self) { 72 | self.player = player; 73 | self.player.delegate = self; 74 | } 75 | return self; 76 | } 77 | 78 | + (instancetype)wrapperWithPlayer:(APAudioPlayer *)player 79 | { 80 | return [[self alloc] initWithPlayer:player]; 81 | } 82 | 83 | - (void)dealloc 84 | { 85 | [self _killDownloadTimer]; 86 | [self _killTimer]; 87 | } 88 | 89 | #pragma mark - Public 90 | 91 | - (void)startPlayingTrackWithURL:(NSURL *)url 92 | { 93 | [self.player loadItemWithURL:url autoPlay:NO]; 94 | [self play]; 95 | [self _startDownloadTimer]; 96 | } 97 | 98 | - (BOOL)isPlaying 99 | { 100 | return self.player.isPlaying; 101 | } 102 | 103 | - (void)play 104 | { 105 | if (self.progressTimer) { 106 | [self _killTimer]; 107 | } 108 | 109 | [self.player play]; 110 | self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.5f 111 | target:self 112 | selector:@selector(progressTimerFired:) 113 | userInfo:nil 114 | repeats:YES]; 115 | } 116 | 117 | - (void)pause 118 | { 119 | [self.player pause]; 120 | [self _killTimer]; 121 | } 122 | 123 | - (void)cleanUp 124 | { 125 | [self _killDownloadTimer]; 126 | [self _killTimer]; 127 | } 128 | 129 | #pragma mark - APAudioPlayerDelegate 130 | 131 | - (void)playerDidChangePlayingStatus:(APAudioPlayer *)player 132 | { 133 | if ([player isPlaying]) { 134 | if ([self.delegate respondsToSelector:@selector(playerDidStartPlaying:)]) { 135 | [self.delegate playerDidStartPlaying:self]; 136 | } 137 | } 138 | else if (player.position != 1.0f) { 139 | if ([self.delegate respondsToSelector:@selector(playerDidPause:)]) { 140 | [self.delegate playerDidPause:self]; 141 | } 142 | } 143 | } 144 | 145 | - (void)playerDidFinishPlaying:(APAudioPlayer *)player 146 | { 147 | [self _startDownloadTimer]; 148 | if ([self.delegate respondsToSelector:@selector(playerDidFinishCurrentTrack:)]) { 149 | [self.delegate playerDidFinishCurrentTrack:self]; 150 | } 151 | [self play]; 152 | } 153 | 154 | - (void)playerBeginInterruption:(APAudioPlayer *)player 155 | { 156 | [self pause]; 157 | } 158 | 159 | - (void)playerEndInterruption:(APAudioPlayer *)player 160 | shouldResume:(BOOL)should 161 | { 162 | [self play]; 163 | } 164 | 165 | #pragma mark - Timers 166 | 167 | - (void)progressTimerFired:(NSTimer *)sender 168 | { 169 | CGFloat playbackProgress = self.player.position; 170 | if ([self.delegate respondsToSelector:@selector(playerWrapper:playbackProgressChanged:)]) { 171 | [self.delegate playerWrapper:self playbackProgressChanged:playbackProgress]; 172 | } 173 | } 174 | 175 | - (void)downloadTimerFired:(NSTimer *)sender 176 | { 177 | self.downloadTicksCount --; 178 | self.downloadProgress += 1.0f / VOXDownloadTicksCount; 179 | if ([self.delegate respondsToSelector:@selector(playerWrapper:downloadProgressChanged:)]) { 180 | [self.delegate playerWrapper:self downloadProgressChanged:self.downloadProgress]; 181 | } 182 | if (self.downloadTicksCount == 0) { 183 | [self _killDownloadTimer]; 184 | } 185 | } 186 | 187 | #pragma mark - Helpers 188 | 189 | - (void)_killTimer 190 | { 191 | [self.progressTimer invalidate]; 192 | self.progressTimer = nil; 193 | } 194 | 195 | - (void)_startDownloadTimer 196 | { 197 | self.downloadTicksCount = VOXDownloadTicksCount; 198 | self.downloadProgress = 0.0f; 199 | self.downloadTimer = [NSTimer scheduledTimerWithTimeInterval:0.3f 200 | target:self 201 | selector:@selector(downloadTimerFired:) 202 | userInfo:nil 203 | repeats:YES]; 204 | } 205 | 206 | - (void)_killDownloadTimer 207 | { 208 | [self.downloadTimer invalidate]; 209 | self.downloadTimer = nil; 210 | } 211 | 212 | 213 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/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 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/Resources/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/VOXHistogramView/Resources/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "ipad", 6 | "minimum-system-version" : "7.0", 7 | "extent" : "full-screen", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "landscape", 12 | "idiom" : "ipad", 13 | "minimum-system-version" : "7.0", 14 | "extent" : "full-screen", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "orientation" : "landscape", 19 | "idiom" : "ipad", 20 | "minimum-system-version" : "7.0", 21 | "extent" : "full-screen", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "orientation" : "portrait", 26 | "idiom" : "iphone", 27 | "minimum-system-version" : "7.0", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "minimum-system-version" : "7.0", 34 | "subtype" : "retina4", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "orientation" : "portrait", 39 | "idiom" : "ipad", 40 | "minimum-system-version" : "7.0", 41 | "extent" : "full-screen", 42 | "scale" : "1x" 43 | } 44 | ], 45 | "info" : { 46 | "version" : 1, 47 | "author" : "xcode" 48 | } 49 | } -------------------------------------------------------------------------------- /Example/VOXHistogramView/Resources/levels.json: -------------------------------------------------------------------------------- 1 | [ 2 | 0.6595238095238095, 3 | 0.8738095238095238, 4 | 0.87142857142857143333333333333333333333, 5 | 0.85952380952380953333333333333333333333, 6 | 0.84047619047619046666666666666666666666, 7 | 0.85476190476190476666666666666666666666, 8 | 0.8785714285714286, 9 | 0.9, 10 | 0.86190476190476193333333333333333333333, 11 | 0.85952380952380953333333333333333333333, 12 | 0.8880952380952381, 13 | 0.90238095238095236666666666666666666666, 14 | 0.94523809523809523333333333333333333333, 15 | 0.8761904761904762, 16 | 0.87857142857142856666666666666666666666, 17 | 0.8857142857142857, 18 | 0.87857142857142856666666666666666666666, 19 | 0.88095238095238093333333333333333333333, 20 | 0.84523809523809526666666666666666666666, 21 | 0.88095238095238093333333333333333333333, 22 | 0.9023809523809524, 23 | 0.84285714285714283333333333333333333333, 24 | 0.9023809523809524, 25 | 0.85, 26 | 0.8738095238095238, 27 | 0.89761904761904763333333333333333333333, 28 | 0.87142857142857143333333333333333333333, 29 | 0.86666666666666666666666666666666666666, 30 | 0.87857142857142856666666666666666666666, 31 | 0.90714285714285716666666666666666666666, 32 | 0.88571428571428573333333333333333333333, 33 | 0.85714285714285716666666666666666666666, 34 | 0.90476190476190476666666666666666666666, 35 | 0.89285714285714283333333333333333333333, 36 | 0.86904761904761906666666666666666666666, 37 | 0.8738095238095238, 38 | 0.89047619047619046666666666666666666666, 39 | 0.90714285714285713333333333333333333333, 40 | 0.87857142857142856666666666666666666666, 41 | 0.85952380952380953333333333333333333333, 42 | 0.8785714285714286, 43 | 0.9166666666666667, 44 | 0.9119047619047619, 45 | 0.87380952380952383333333333333333333333, 46 | 0.8833333333333333, 47 | 0.89047619047619046666666666666666666666, 48 | 0.8619047619047619, 49 | 0.88333333333333333333333333333333333333, 50 | 0.89285714285714283333333333333333333333, 51 | 0.8880952380952381, 52 | 0.9023809523809524, 53 | 0.89523809523809523333333333333333333333, 54 | 0.8880952380952381, 55 | 0.85, 56 | 0.8523809523809524, 57 | 0.90714285714285713333333333333333333333, 58 | 0.8761904761904762, 59 | 0.84523809523809526666666666666666666666, 60 | 0.8738095238095238, 61 | 0.8619047619047619, 62 | 0.8738095238095238, 63 | 0.90714285714285713333333333333333333333, 64 | 0.85714285714285716666666666666666666666, 65 | 0.8880952380952381, 66 | 0.86428571428571426666666666666666666666, 67 | 0.9095238095238095, 68 | 0.8761904761904762, 69 | 0.85952380952380953333333333333333333333, 70 | 0.90714285714285716666666666666666666666, 71 | 0.8761904761904762, 72 | 0.8880952380952381, 73 | 0.90714285714285716666666666666666666666, 74 | 0.84523809523809523333333333333333333333, 75 | 0.9, 76 | 0.88571428571428573333333333333333333333, 77 | 0.89523809523809523333333333333333333333, 78 | 0.89761904761904763333333333333333333333, 79 | 0.90476190476190476666666666666666666666, 80 | 0.89761904761904763333333333333333333333, 81 | 0.8857142857142857, 82 | 0.8761904761904762, 83 | 0.87142857142857143333333333333333333333, 84 | 0.89047619047619046666666666666666666666, 85 | 0.8666666666666667, 86 | 0.85476190476190476666666666666666666666, 87 | 0.8880952380952381, 88 | 0.87380952380952383333333333333333333333, 89 | 0.86904761904761903333333333333333333333, 90 | 0.92619047619047616666666666666666666666, 91 | 0.88333333333333333333333333333333333333, 92 | 0.85, 93 | 0.85952380952380953333333333333333333333, 94 | 0.8619047619047619, 95 | 0.8738095238095238, 96 | 0.86666666666666666666666666666666666666, 97 | 0.8880952380952381, 98 | 0.86904761904761906666666666666666666666, 99 | 0.8880952380952381, 100 | 0.90952380952380953333333333333333333333, 101 | 0.8738095238095238, 102 | 0.8642857142857143, 103 | 0.8880952380952381, 104 | 0.88095238095238096666666666666666666666, 105 | 0.87619047619047616666666666666666666666, 106 | 0.8642857142857143, 107 | 0.8976190476190476, 108 | 0.86428571428571426666666666666666666666, 109 | 0.9095238095238095, 110 | 0.94047619047619046666666666666666666666, 111 | 0.8857142857142857, 112 | 0.90476190476190473333333333333333333333, 113 | 0.88333333333333333333333333333333333333, 114 | 0.90238095238095236666666666666666666666, 115 | 0.88809523809523806666666666666666666666, 116 | 0.8714285714285714, 117 | 0.87142857142857143333333333333333333333, 118 | 0.8619047619047619, 119 | 0.85, 120 | 0.88333333333333333333333333333333333333, 121 | 0.87380952380952383333333333333333333333, 122 | 0.84999999999999996666666666666666666666, 123 | 0.9261904761904762, 124 | 0.9142857142857143, 125 | 0.88333333333333333333333333333333333333, 126 | 0.8595238095238095, 127 | 0.70952380952380953333333333333333333333, 128 | 0.09047619047619048, 129 | 0.09047619047619048, 130 | 0.09047619047619048, 131 | 0.09523809523809524, 132 | 0.09523809523809524, 133 | 0.09523809523809524, 134 | 0.09523809523809524, 135 | 0.09761904761904762, 136 | 0.09523809523809524, 137 | 0.09285714285714286, 138 | 0.1, 139 | 0.09285714285714286, 140 | 0.102380952380952366666666666666666666666, 141 | 0.09761904761904762, 142 | 0.1, 143 | 0.09761904761904762, 144 | 0.102380952380952366666666666666666666666, 145 | 0.1, 146 | 0.09761904761904762, 147 | 0.1, 148 | 0.09761904761904762, 149 | 0.1, 150 | 0.09523809523809524, 151 | 0.102380952380952366666666666666666666666, 152 | 0.09761904761904762, 153 | 0.1, 154 | 0.09761904761904762, 155 | 0.09523809523809524, 156 | 0.102380952380952366666666666666666666666, 157 | 0.1, 158 | 0.1, 159 | 0.1, 160 | 0.09761904761904762, 161 | 0.1, 162 | 0.1, 163 | 0.1, 164 | 0.1, 165 | 0.1, 166 | 0.09761904761904762, 167 | 0.1, 168 | 0.1, 169 | 0.09761904761904762, 170 | 0.1, 171 | 0.1, 172 | 0.1, 173 | 0.09523809523809524, 174 | 0.1, 175 | 0.1, 176 | 0.1, 177 | 0.102380952380952366666666666666666666666, 178 | 0.1, 179 | 0.09761904761904762, 180 | 0.099999999999999986666666666666666666666, 181 | 0.09523809523809524, 182 | 0.09761904761904762, 183 | 0.1, 184 | 0.1, 185 | 0.1, 186 | 0.1, 187 | 0.1, 188 | 0.102380952380952366666666666666666666666, 189 | 0.09761904761904762, 190 | 0.1, 191 | 0.1, 192 | 0.09761904761904762, 193 | 0.09523809523809524, 194 | 0.099999999999999986666666666666666666666, 195 | 0.09761904761904762, 196 | 0.1, 197 | 0.09761904761904762, 198 | 0.09761904761904762, 199 | 0.1, 200 | 0.1, 201 | 0.09761904761904762, 202 | 0.1, 203 | 0.09761904761904762, 204 | 0.1, 205 | 0.1, 206 | 0.09761904761904762, 207 | 0.099999999999999986666666666666666666666, 208 | 0.1, 209 | 0.09761904761904762, 210 | 0.09761904761904762, 211 | 0.1, 212 | 0.09761904761904762, 213 | 0.09761904761904762, 214 | 0.09761904761904762, 215 | 0.09761904761904762, 216 | 0.1, 217 | 0.1, 218 | 0.09761904761904762, 219 | 0.1, 220 | 0.09285714285714286, 221 | 0.1, 222 | 0.09761904761904762, 223 | 0.1, 224 | 0.099999999999999986666666666666666666666, 225 | 0.1, 226 | 0.099999999999999986666666666666666666666, 227 | 0.1, 228 | 0.1, 229 | 0.099999999999999986666666666666666666666, 230 | 0.1, 231 | 0.1, 232 | 0.1, 233 | 0.09761904761904762, 234 | 0.1, 235 | 0.09523809523809524, 236 | 0.09761904761904762, 237 | 0.09761904761904762, 238 | 0.1, 239 | 0.09761904761904762, 240 | 0.1, 241 | 0.1, 242 | 0.1, 243 | 0.1, 244 | 0.1, 245 | 0.09761904761904762, 246 | 0.09761904761904762, 247 | 0.09761904761904762, 248 | 0.1, 249 | 0.1, 250 | 0.09761904761904762, 251 | 0.1 252 | ] -------------------------------------------------------------------------------- /Example/VOXHistogramView/Resources/pink20silence20.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coppertino/VOXHistogramView/aae79f0089eb3d724c3ecb689c061fd0d731fe9f/Example/VOXHistogramView/Resources/pink20silence20.mp3 -------------------------------------------------------------------------------- /Example/VOXHistogramView/VOXAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 02.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXAppDelegate : UIResponder 32 | 33 | 34 | @property(strong, nonatomic) UIWindow *window; 35 | 36 | 37 | @end 38 | 39 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/VOXAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 02.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXAppDelegate.h" 28 | 29 | 30 | 31 | @interface VOXAppDelegate () 32 | 33 | @end 34 | 35 | 36 | 37 | @implementation VOXAppDelegate 38 | 39 | 40 | - (BOOL) application:(UIApplication *)application 41 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 42 | { 43 | // Override point for customization after application launch. 44 | return YES; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/VOXHistogramView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/VOXHistogramView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXControlHistogramViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 24.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXControlHistogramViewController : UIViewController 32 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXControlHistogramViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 24.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXControlHistogramViewController.h" 28 | #import "VOXJSONConverter.h" 29 | #import "VOXPlayerWrapper.h" 30 | #import 31 | 32 | 33 | 34 | @interface VOXControlHistogramViewController () 35 | 36 | 37 | #pragma mark - Outlets 38 | @property(weak, nonatomic) IBOutlet UIButton *playButton; 39 | @property(weak, nonatomic) IBOutlet VOXHistogramControlView *histogramControlView; 40 | @property(weak, nonatomic) IBOutlet UILabel *scrubbingSpeedLabel; 41 | 42 | #pragma mark - Player Wrapper 43 | @property(nonatomic, strong) VOXPlayerWrapper *playerWrapper; 44 | @end 45 | 46 | 47 | 48 | @implementation VOXControlHistogramViewController 49 | 50 | 51 | #pragma mark - Lifecycle 52 | 53 | - (void)viewDidLoad 54 | { 55 | [super viewDidLoad]; 56 | 57 | self.histogramControlView.delegate = self; 58 | 59 | self.playerWrapper = [[VOXPlayerWrapper alloc] initWithPlayer:[APAudioPlayer new]]; 60 | self.playerWrapper.delegate = self; 61 | 62 | self.scrubbingSpeedLabel.alpha = 0.0f; 63 | } 64 | 65 | - (void)viewDidAppear:(BOOL)animated 66 | { 67 | [super viewDidAppear:animated]; 68 | 69 | /* Load levels JSON */ 70 | NSArray *levels = [VOXJSONConverter jsonObjectWithFileName:@"levels.json"]; 71 | self.histogramControlView.levels = levels; 72 | 73 | NSString *path = [[NSBundle mainBundle] pathForResource:@"pink20silence20" ofType:@"mp3"]; 74 | [self.playerWrapper startPlayingTrackWithURL:[NSURL URLWithString:path]]; 75 | } 76 | 77 | - (void)dealloc 78 | { 79 | [self.playerWrapper cleanUp]; 80 | } 81 | 82 | 83 | #pragma mark - Actions 84 | 85 | - (IBAction)playButtonTap:(id)sender 86 | { 87 | if ([self.playerWrapper isPlaying]) { 88 | [self.playerWrapper pause]; 89 | } 90 | else { 91 | [self.playerWrapper play]; 92 | } 93 | } 94 | 95 | #pragma mark - VOXPlayerWrapperDelegate 96 | 97 | - (void)playerDidPause:(VOXPlayerWrapper *)playerWrapper 98 | { 99 | [self.playButton setTitle:@"Play" forState:UIControlStateNormal]; 100 | [self.histogramControlView hideHistogramViewAnimated:YES]; 101 | } 102 | 103 | - (void)playerDidStartPlaying:(VOXPlayerWrapper *)playerWrapper 104 | { 105 | [self.playButton setTitle:@"Pause" forState:UIControlStateNormal]; 106 | [self.histogramControlView showHistogramViewAnimated:YES]; 107 | } 108 | 109 | - (void)playerDidFinishCurrentTrack:(VOXPlayerWrapper *)playerWrapper 110 | { 111 | self.histogramControlView.playbackProgress = 0.0f; 112 | } 113 | 114 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 115 | downloadProgressChanged:(CGFloat)downloadProgress 116 | { 117 | self.histogramControlView.downloadProgress = downloadProgress; 118 | } 119 | 120 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 121 | playbackProgressChanged:(CGFloat)playbackProgress 122 | { 123 | self.histogramControlView.playbackProgress = playbackProgress; 124 | } 125 | 126 | #pragma mark - VOXHistogramControlViewDelegate 127 | 128 | - (void)histogramControlViewDidFinishRendering:(VOXHistogramControlView *)controlView 129 | { 130 | [self.histogramControlView showHistogramViewAnimated:YES]; 131 | } 132 | 133 | - (void)histogramControlView:(VOXHistogramControlView *)controlView 134 | didChangeScrubbingSpeed:(CGFloat)scrubbingSpeed 135 | { 136 | [self _updateScrubbingSpeedLabel:scrubbingSpeed]; 137 | } 138 | 139 | - (void)histogramControlViewDidStartTracking:(VOXHistogramControlView *)controlView 140 | { 141 | [self.histogramControlView showHistogramViewAnimated:YES]; 142 | [self _animateScrubbingSpeedLabel:YES]; 143 | [self _updateScrubbingSpeedLabel:controlView.scrubbingSpeed]; 144 | } 145 | 146 | - (void) histogramControlView:(VOXHistogramControlView *)controlView 147 | didFinishTrackingWithProgress:(CGFloat)value 148 | { 149 | if (! [self.playerWrapper isPlaying]) { 150 | [self.histogramControlView hideHistogramViewAnimated:YES]; 151 | } 152 | [self _animateScrubbingSpeedLabel:NO]; 153 | self.playerWrapper.position = value; 154 | } 155 | 156 | #pragma mark - Private 157 | 158 | - (void)_updateScrubbingSpeedLabel:(CGFloat)scrubbingSpeed 159 | { 160 | self.scrubbingSpeedLabel.text = [NSString stringWithFormat:@"%@: %.0f%%", NSLocalizedString(@"Scrubbing speed", nil), 161 | scrubbingSpeed * 100]; 162 | } 163 | 164 | - (void)_animateScrubbingSpeedLabel:(BOOL)show 165 | { 166 | [UIView animateWithDuration:0.25f animations:^{ 167 | self.scrubbingSpeedLabel.alpha = show ? 1.0f : 0.0f; 168 | }]; 169 | } 170 | 171 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXSimpleHistogramViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 02.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXSimpleHistogramViewController : UIViewController 32 | 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXSimpleHistogramViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 02.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import "VOXSimpleHistogramViewController.h" 32 | #import "VOXJSONConverter.h" 33 | #import "VOXPlayerWrapper.h" 34 | 35 | 36 | 37 | @interface VOXSimpleHistogramViewController () 38 | 39 | 40 | #pragma mark - Outlets 41 | @property(weak, nonatomic) IBOutlet UIButton *playButton; 42 | @property(weak, nonatomic) IBOutlet VOXHistogramView *histogramView; 43 | 44 | #pragma mark - Player 45 | @property(nonatomic, strong) VOXPlayerWrapper *playerWrapper; 46 | 47 | @end 48 | 49 | 50 | 51 | @implementation VOXSimpleHistogramViewController 52 | 53 | 54 | #pragma mark - Lifecycle 55 | 56 | - (void)viewDidLoad 57 | { 58 | [super viewDidLoad]; 59 | 60 | self.playerWrapper = [[VOXPlayerWrapper alloc] initWithPlayer:[APAudioPlayer new]]; 61 | self.playerWrapper.delegate = self; 62 | } 63 | 64 | - (void)viewDidAppear:(BOOL)animated 65 | { 66 | [super viewDidAppear:animated]; 67 | 68 | /* Histogram params */ 69 | NSUInteger peakWidth = 4; 70 | NSUInteger marginWidth = 2; 71 | 72 | /* Setup rendering configuration */ 73 | VOXHistogramRenderingConfiguration *renderingConfiguration = [VOXHistogramRenderingConfiguration new]; 74 | renderingConfiguration.outputImageSize = self.histogramView.bounds.size; 75 | renderingConfiguration.renderingMode = UIImageRenderingModeAlwaysTemplate; 76 | renderingConfiguration.peaksColor = [UIColor whiteColor]; 77 | renderingConfiguration.peakWidth = peakWidth; 78 | renderingConfiguration.marginWidth = marginWidth; 79 | 80 | /* Create renderer for histogram image */ 81 | VOXHistogramRenderer *renderer = [VOXHistogramRenderer rendererWithRenderingConfiguration:renderingConfiguration]; 82 | 83 | /* Load levels JSON */ 84 | NSArray *levels = [VOXJSONConverter jsonObjectWithFileName:@"levels.json"]; 85 | 86 | /* Setup levels converter */ 87 | VOXHistogramLevelsConverter *converter = [VOXHistogramLevelsConverter new]; 88 | [converter updateLevels:levels]; 89 | 90 | /* Calculate number of levels that histogram can display in current bounds */ 91 | NSUInteger samplingRate = [self _samplingRateForHistogramWidth:CGRectGetWidth(self.histogramView.bounds) 92 | peakWidth:peakWidth 93 | marginWidth:marginWidth]; 94 | 95 | /* Convert levels array to sampling rate and render histogram image */ 96 | [converter calculateLevelsForSamplingRate:samplingRate completion:^(NSArray *levelsResampled) { 97 | [renderer renderHistogramWithLevels:levelsResampled completion:^(UIImage *image) {\ 98 | self.histogramView.image = image; 99 | }]; 100 | }]; 101 | 102 | NSString *path = [[NSBundle mainBundle] pathForResource:@"pink20silence20" ofType:@"mp3"]; 103 | [self.playerWrapper startPlayingTrackWithURL:[NSURL URLWithString:path]]; 104 | } 105 | 106 | - (void)dealloc 107 | { 108 | [self.playerWrapper cleanUp]; 109 | } 110 | 111 | 112 | #pragma mark - Actions 113 | 114 | - (IBAction)playButtonTap:(id)sender 115 | { 116 | if ([self.playerWrapper isPlaying]) { 117 | [self.playerWrapper pause]; 118 | } 119 | else { 120 | [self.playerWrapper play]; 121 | } 122 | } 123 | 124 | #pragma mark - VOXPlayerWrapperDelegate 125 | 126 | - (void)playerDidPause:(VOXPlayerWrapper *)playerWrapper 127 | { 128 | [self.playButton setTitle:@"Play" forState:UIControlStateNormal]; 129 | } 130 | 131 | - (void)playerDidStartPlaying:(VOXPlayerWrapper *)playerWrapper 132 | { 133 | [self.playButton setTitle:@"Pause" forState:UIControlStateNormal]; 134 | } 135 | 136 | - (void)playerDidFinishCurrentTrack:(VOXPlayerWrapper *)playerWrapper 137 | { 138 | [self.histogramView updatePlaybackProgress:0.0f]; 139 | } 140 | 141 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 142 | playbackProgressChanged:(CGFloat)playbackProgress 143 | { 144 | [self.histogramView updatePlaybackProgress:playbackProgress]; 145 | } 146 | 147 | - (void) playerWrapper:(VOXPlayerWrapper *)playerWrapper 148 | downloadProgressChanged:(CGFloat)downloadProgress 149 | { 150 | [self.histogramView updateDownloadProgress:downloadProgress]; 151 | } 152 | 153 | #pragma mark - Private 154 | 155 | - (NSUInteger)_samplingRateForHistogramWidth:(CGFloat)histogramWidth 156 | peakWidth:(CGFloat)peakWidth 157 | marginWidth:(CGFloat)marginWidth 158 | { 159 | CGFloat scale = [UIScreen mainScreen].scale; 160 | return (NSUInteger) ceilf((histogramWidth / (peakWidth + marginWidth)) * scale); 161 | } 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 17.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXTableViewController : UITableViewController 32 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/ViewControllers/VOXTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 17.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXTableViewController.h" 28 | 29 | 30 | 31 | @implementation VOXTableViewController 32 | 33 | 34 | @end -------------------------------------------------------------------------------- /Example/VOXHistogramView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/VOXHistogramView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VOXHistogramView 4 | // 5 | // Created by Nickolay Sheika on 06/27/2015. 6 | // Copyright (c) 2014 Nickolay Sheika. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "VOXAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([VOXAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Gif/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coppertino/VOXHistogramView/aae79f0089eb3d724c3ecb689c061fd0d731fe9f/Gif/demo.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Coppertino Inc. (http://coppertino.com/) 2 | 3 | VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 4 | Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 5 | Contact phone: +1 (888) 765-7069 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. -------------------------------------------------------------------------------- /Pod/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coppertino/VOXHistogramView/aae79f0089eb3d724c3ecb689c061fd0d731fe9f/Pod/Assets/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coppertino/VOXHistogramView/aae79f0089eb3d724c3ecb689c061fd0d731fe9f/Pod/Classes/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/Animator/VOXHistogramAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 23.01.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | @class VOXHistogramAnimator; 30 | 31 | 32 | 33 | @protocol VOXHistogramAnimatorDelegate 34 | 35 | 36 | - (void)histogramAnimatorWillShowHistogram:(VOXHistogramAnimator *)controlView; 37 | - (void)histogramAnimatorDidShowHistogram:(VOXHistogramAnimator *)controlView; 38 | - (void)histogramAnimatorWillHideHistogram:(VOXHistogramAnimator *)controlView; 39 | - (void)histogramAnimatorDidHideHistogram:(VOXHistogramAnimator *)controlView; 40 | 41 | @end 42 | 43 | 44 | 45 | @interface VOXHistogramAnimator : NSObject 46 | 47 | 48 | #pragma mark - Delegate 49 | @property(nonatomic, weak) id delegate; 50 | 51 | #pragma mark - State 52 | @property(nonatomic, assign, readonly) BOOL histogramPresented; 53 | @property(nonatomic, assign, readonly) BOOL animating; 54 | 55 | #pragma mark - Managed Views 56 | @property(nonatomic, weak, readonly) UIView *histogramView; 57 | 58 | #pragma mark - Show / Hide Histogram 59 | - (void)showHistogramViewAnimated:(BOOL)animated; 60 | - (void)hideHistogramViewAnimated:(BOOL)animated; 61 | 62 | #pragma mark - Designated Initializer 63 | - (instancetype)initWithHistogramView:(UIView *)histogramView; 64 | + (instancetype)animatorWithHistogramView:(UIView *)histogramView; 65 | 66 | 67 | @end -------------------------------------------------------------------------------- /Pod/Classes/Animator/VOXHistogramAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 23.01.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXHistogramAnimator.h" 28 | 29 | static CGFloat const VOXHistogramAnimatorAnimationDuration = 0.25f; 30 | 31 | 32 | 33 | @interface VOXHistogramAnimator () 34 | 35 | 36 | #pragma mark - Public 37 | @property(nonatomic, weak, readwrite) UIView *histogramView; 38 | @property(nonatomic, assign, readwrite, getter=didHistogramShowed) BOOL histogramPresented; 39 | 40 | #pragma mark - Helpers 41 | @property(nonatomic, assign) BOOL animatingShowHistogram; 42 | @property(nonatomic, assign) BOOL animatingHideHistogram; 43 | 44 | @end 45 | 46 | 47 | 48 | @implementation VOXHistogramAnimator 49 | 50 | 51 | #pragma mark - Accessors 52 | 53 | - (BOOL)animating 54 | { 55 | return self.animatingHideHistogram || self.animatingShowHistogram; 56 | } 57 | 58 | #pragma mark - Init 59 | 60 | - (instancetype)initWithHistogramView:(UIView *)histogramView 61 | { 62 | self = [super init]; 63 | if (self) { 64 | self.histogramView = histogramView; 65 | self.histogramPresented = YES; 66 | } 67 | return self; 68 | } 69 | 70 | + (instancetype)animatorWithHistogramView:(UIView *)histogramView 71 | { 72 | return [[self alloc] initWithHistogramView:histogramView]; 73 | } 74 | 75 | #pragma mark - Public 76 | 77 | - (void)showHistogramViewAnimated:(BOOL)animated 78 | { 79 | if ((self.histogramPresented && ! self.animatingHideHistogram) || self.animatingShowHistogram) 80 | return; 81 | 82 | if ([self.delegate respondsToSelector:@selector(histogramAnimatorWillShowHistogram:)]) { 83 | [self.delegate histogramAnimatorWillShowHistogram:self]; 84 | } 85 | 86 | void (^animations)() = ^{ 87 | [self transformToShowedState]; 88 | }; 89 | void (^completion)(BOOL) = ^(BOOL finished) { 90 | self.animatingShowHistogram = NO; 91 | if (finished) { 92 | self.histogramPresented = YES; 93 | if ([self.delegate respondsToSelector:@selector(histogramAnimatorDidShowHistogram:)]) { 94 | [self.delegate histogramAnimatorDidShowHistogram:self]; 95 | } 96 | } 97 | }; 98 | 99 | if (animated) { 100 | self.animatingShowHistogram = YES; 101 | [self makeTransitionAnimationWithAnimations:animations 102 | andCompletion:completion]; 103 | } 104 | else { 105 | animations(); 106 | completion(YES); 107 | } 108 | } 109 | 110 | - (void)hideHistogramViewAnimated:(BOOL)animated 111 | { 112 | if ((! self.histogramPresented && ! self.animatingShowHistogram) || self.animatingHideHistogram) 113 | return; 114 | 115 | if ([self.delegate respondsToSelector:@selector(histogramAnimatorWillHideHistogram:)]) { 116 | [self.delegate histogramAnimatorWillHideHistogram:self]; 117 | } 118 | 119 | void (^animations)() = ^{ 120 | [self transformToHiddenState]; 121 | }; 122 | void (^completion)(BOOL) = ^(BOOL finished) { 123 | self.animatingHideHistogram = NO; 124 | if (finished) { 125 | self.histogramPresented = NO; 126 | if ([self.delegate respondsToSelector:@selector(histogramAnimatorDidHideHistogram:)]) { 127 | [self.delegate histogramAnimatorDidHideHistogram:self]; 128 | } 129 | } 130 | }; 131 | 132 | if (animated) { 133 | self.animatingHideHistogram = YES; 134 | [self makeTransitionAnimationWithAnimations:animations 135 | andCompletion:completion]; 136 | } 137 | else { 138 | animations(); 139 | completion(YES); 140 | } 141 | } 142 | 143 | #pragma mark - Animations 144 | 145 | - (void)makeTransitionAnimationWithAnimations:(void (^)(void))animations 146 | andCompletion:(void (^)(BOOL finished))completion 147 | { 148 | [UIView animateWithDuration:VOXHistogramAnimatorAnimationDuration 149 | delay:0.0f 150 | usingSpringWithDamping:0.9f 151 | initialSpringVelocity:0.8f 152 | options:UIViewAnimationOptionBeginFromCurrentState 153 | animations:animations 154 | completion:completion]; 155 | } 156 | 157 | #pragma mark - Frames Setup 158 | 159 | - (void)transformToHiddenState 160 | { 161 | CGFloat histogramHeight = CGRectGetHeight(self.histogramView.frame); 162 | CGAffineTransform translation = CGAffineTransformMakeTranslation(0.0f, histogramHeight / 2); 163 | CGAffineTransform scale = CGAffineTransformMakeScale(1.0f, 0.00001f); 164 | CGAffineTransform transform = CGAffineTransformConcat(scale, translation); 165 | self.histogramView.transform = transform; 166 | } 167 | 168 | - (void)transformToShowedState 169 | { 170 | self.histogramView.transform = CGAffineTransformIdentity; 171 | } 172 | 173 | @end -------------------------------------------------------------------------------- /Pod/Classes/Categories/UIView+Autolayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 25.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface UIView (Autolayout) 32 | 33 | + (instancetype)autolayoutView; 34 | 35 | @end -------------------------------------------------------------------------------- /Pod/Classes/Categories/UIView+Autolayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 25.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "UIView+Autolayout.h" 28 | 29 | 30 | 31 | @implementation UIView (Autolayout) 32 | 33 | 34 | + (instancetype)autolayoutView 35 | { 36 | UIView *view = [[self alloc] initWithFrame:CGRectZero]; 37 | view.translatesAutoresizingMaskIntoConstraints = NO; 38 | return view; 39 | } 40 | 41 | 42 | @end -------------------------------------------------------------------------------- /Pod/Classes/Configurations/VOXHistogramRenderingConfiguration.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 14.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXHistogramRenderingConfiguration : NSObject 32 | 33 | /** 34 | * Size of resulting image 35 | */ 36 | @property(nonatomic, assign) CGSize outputImageSize; 37 | 38 | /** 39 | * Image rendering mode 40 | */ 41 | @property(nonatomic, assign) UIImageRenderingMode renderingMode; 42 | 43 | /** 44 | * Width if one peak in pixels (not points!) 45 | */ 46 | @property(nonatomic, assign) NSUInteger peakWidth; 47 | 48 | /** 49 | * Margin between two peaks in pixels (not points!) 50 | */ 51 | @property(nonatomic, assign) NSUInteger marginWidth; 52 | 53 | /** 54 | * Color of peaks 55 | */ 56 | @property(nonatomic, strong) UIColor *peaksColor; 57 | 58 | @end -------------------------------------------------------------------------------- /Pod/Classes/Configurations/VOXHistogramRenderingConfiguration.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 14.06.15. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXHistogramRenderingConfiguration.h" 28 | 29 | 30 | 31 | @implementation VOXHistogramRenderingConfiguration 32 | 33 | 34 | @end -------------------------------------------------------------------------------- /Pod/Classes/LevelsConverter/VOXHistogramLevelsConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/9/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXHistogramLevelsConverter : NSObject 32 | 33 | 34 | /* 35 | @value full levels array 36 | */ 37 | @property(nonatomic, strong, readonly) NSArray *levels; 38 | 39 | #pragma mark - Data Updating 40 | - (void)updateLevels:(NSArray *)levels; 41 | 42 | #pragma mark - Get histogram data 43 | - (void)calculateLevelsForSamplingRate:(NSUInteger)samplingRate 44 | completion:(void (^)(NSArray *levels))completion; 45 | 46 | 47 | @end -------------------------------------------------------------------------------- /Pod/Classes/LevelsConverter/VOXHistogramLevelsConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/9/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXHistogramLevelsConverter.h" 28 | #import "macros_blocks.h" 29 | 30 | 31 | static NSUInteger const averagingWindow = 3; 32 | 33 | 34 | 35 | @implementation VOXHistogramLevelsConverter 36 | 37 | 38 | #pragma mark - Public 39 | 40 | - (void)updateLevels:(NSArray *)levels 41 | { 42 | _levels = levels; 43 | } 44 | 45 | - (void)calculateLevelsForSamplingRate:(NSUInteger)samplingRate 46 | completion:(void (^)(NSArray *levels))completion; 47 | { 48 | NSUInteger samplesCount = [self.levels count]; 49 | 50 | if (samplingRate == 0 || self.levels == nil) { 51 | safe_block(completion, nil); 52 | } 53 | 54 | if (samplingRate == samplesCount) { 55 | safe_block(completion, self.levels); 56 | return; 57 | } 58 | 59 | if (samplingRate > samplesCount) { 60 | [NSException raise:NSInvalidArgumentException format:@"samplingRate cannot be more than levels count!"]; 61 | } 62 | 63 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 64 | 65 | NSMutableArray *result = [NSMutableArray array]; 66 | @autoreleasepool { 67 | 68 | CGFloat downSamplingRatio = (CGFloat) samplesCount / samplingRate; 69 | for (NSUInteger i = 1; i <= samplingRate; i ++) { 70 | 71 | NSUInteger windowPosition = (NSUInteger) floorf(i * downSamplingRatio - downSamplingRatio / 2); 72 | 73 | NSInteger windowStart = windowPosition - (NSInteger) floorf(averagingWindow / 2); 74 | NSInteger windowFinish = windowStart + averagingWindow - 1; 75 | NSUInteger windowStartNormalized = (NSUInteger) (windowStart < 0 ? 0 : windowStart); 76 | NSUInteger windowFinishNormalized = windowFinish > (samplesCount - 1) ? samplesCount - 1 : (NSUInteger) windowFinish; 77 | NSRange windowRange = NSMakeRange(windowStartNormalized, windowFinishNormalized - windowStartNormalized + 1); 78 | 79 | NSArray *subArray = [self.levels subarrayWithRange:windowRange]; 80 | NSNumber *average = [subArray valueForKeyPath:@"@avg.self"]; 81 | [result addObject:average]; 82 | } 83 | } 84 | 85 | main_queue_block(completion, [result copy]); 86 | }); 87 | } 88 | 89 | @end -------------------------------------------------------------------------------- /Pod/Classes/ProgressLine/VOXProgressLineView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 23.11.14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXProgressLineView : UIView 32 | 33 | 34 | /** 35 | * Colors setup 36 | */ 37 | @property(nonatomic, strong) IBInspectable UIColor *completeColor; 38 | @property(nonatomic, strong) IBInspectable UIColor *notCompleteColor; 39 | @property(nonatomic, strong) IBInspectable UIColor *downloadedColor; 40 | 41 | /** 42 | * Update current playback progress from 0.0f to 1.0f 43 | */ 44 | - (void)updatePlaybackProgress:(CGFloat)playbackProgress; 45 | 46 | /** 47 | * Update current download progress from 0.0f to 1.0f 48 | */ 49 | - (void)updateDownloadProgress:(CGFloat)downloadProgress; 50 | 51 | @end -------------------------------------------------------------------------------- /Pod/Classes/ProgressLine/VOXProgressLineView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 23.11.14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXProgressLineView.h" 28 | 29 | 30 | 31 | @interface VOXProgressLineView () 32 | 33 | 34 | @property(nonatomic, assign) CGFloat playbackProgress; 35 | @property(nonatomic, assign) CGFloat downloadProgress; 36 | 37 | @end 38 | 39 | 40 | 41 | @implementation VOXProgressLineView 42 | 43 | 44 | #pragma mark - Init 45 | 46 | - (instancetype)initWithFrame:(CGRect)frame 47 | { 48 | self = [super initWithFrame:frame]; 49 | if (self) { 50 | [self setup]; 51 | } 52 | return self; 53 | } 54 | 55 | - (id)initWithCoder:(NSCoder *)coder 56 | { 57 | self = [super initWithCoder:coder]; 58 | if (self) { 59 | [self setup]; 60 | } 61 | return self; 62 | } 63 | 64 | #pragma mark - Setup 65 | 66 | - (void)setup 67 | { 68 | // default colors for debugging 69 | self.notCompleteColor = [UIColor greenColor]; 70 | self.completeColor = [UIColor redColor]; 71 | self.downloadedColor = [UIColor yellowColor]; 72 | 73 | // background should be clear 74 | self.backgroundColor = [UIColor clearColor]; 75 | } 76 | 77 | #pragma mark - Public 78 | 79 | - (void)updatePlaybackProgress:(CGFloat)playbackProgress 80 | { 81 | self.playbackProgress = [self _normalizedValue:playbackProgress]; 82 | [self setNeedsDisplay]; 83 | } 84 | 85 | - (void)updateDownloadProgress:(CGFloat)downloadProgress 86 | { 87 | self.downloadProgress = [self _normalizedDownloadProgressValue:downloadProgress]; 88 | [self setNeedsDisplay]; 89 | } 90 | 91 | #pragma mark - Drawing 92 | 93 | - (void)drawRect:(CGRect)rect 94 | { 95 | [super drawRect:rect]; 96 | 97 | /* Taking graphic context */ 98 | CGContextRef context = UIGraphicsGetCurrentContext(); 99 | 100 | /* Please, no antialiasing */ 101 | CGContextSetShouldAntialias(context, NO); 102 | 103 | // Setting line width 104 | CGContextSetLineWidth(context, rect.size.height); 105 | 106 | // calculate slider line Y position 107 | CGFloat yPosition = rect.size.height / 2; 108 | 109 | // get current rect width 110 | CGFloat rectWidth = rect.size.width; 111 | 112 | 113 | 114 | /* Drawing complete part of slider */ 115 | 116 | // setting line color 117 | CGContextSetStrokeColorWithColor(context, self.completeColor.CGColor); 118 | 119 | // start to draw line from left 120 | CGContextMoveToPoint(context, 0, yPosition); 121 | 122 | // calculating line width for current cursor position 123 | CGFloat lineWidth = self.playbackProgress * rectWidth; 124 | 125 | // drawing line with calculated width 126 | CGContextAddLineToPoint(context, lineWidth, yPosition); 127 | 128 | // draw stroke 129 | CGContextStrokePath(context); 130 | 131 | 132 | 133 | /* Drawing downloaded part of slider */ 134 | 135 | if (self.downloadProgress > self.playbackProgress) { 136 | 137 | // move ahead 138 | CGContextMoveToPoint(context, lineWidth, yPosition); 139 | 140 | // setting line color 141 | CGContextSetStrokeColorWithColor(context, self.downloadedColor.CGColor); 142 | 143 | // calculating line width for current downloaded position 144 | lineWidth = self.downloadProgress * rectWidth; 145 | 146 | // drawing line with calculated width 147 | CGContextAddLineToPoint(context, lineWidth, yPosition); 148 | 149 | // draw stroke 150 | CGContextStrokePath(context); 151 | } 152 | 153 | 154 | 155 | /* Drawing not complete part of slider */ 156 | 157 | // setting line color 158 | CGContextSetStrokeColorWithColor(context, self.notCompleteColor.CGColor); 159 | 160 | // move ahead 161 | CGContextMoveToPoint(context, lineWidth, yPosition); 162 | 163 | // calculating line width for current downloaded position 164 | lineWidth = rectWidth; 165 | 166 | // drawing line with calculated width 167 | CGContextAddLineToPoint(context, lineWidth, yPosition); 168 | 169 | // draw stroke 170 | CGContextStrokePath(context); 171 | } 172 | 173 | #pragma mark - Helpers 174 | 175 | - (CGFloat)_normalizedValue:(CGFloat)value 176 | { 177 | return MAX(MIN(value, 1), 0); 178 | } 179 | 180 | - (CGFloat)_normalizedDownloadProgressValue:(CGFloat)downloadProgressValue 181 | { 182 | return MAX(MIN(downloadProgressValue, 1), self.playbackProgress); 183 | } 184 | 185 | @end -------------------------------------------------------------------------------- /Pod/Classes/Rendering/VOXHistogramRenderer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 09.01.15. 3 | // Copyright (c) 2015 Alterplay. All rights reserved. 4 | // 5 | 6 | #import 7 | #import 8 | 9 | @class VOXHistogramRenderingConfiguration; 10 | 11 | 12 | 13 | @interface VOXHistogramRenderer : NSObject 14 | 15 | 16 | #pragma mark - Init 17 | - (instancetype)initWithRenderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration NS_DESIGNATED_INITIALIZER; 18 | + (instancetype)rendererWithRenderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration; 19 | 20 | 21 | #pragma mark - Rendering 22 | /** 23 | * Will render histogram image on background 24 | * 25 | * @param levels - array of NSNumbers from @0.0f to @1.0f 26 | * @param completion - block will be called when finished rendering 27 | */ 28 | - (void)renderHistogramWithLevels:(NSArray *)levels 29 | completion:(void (^)(UIImage *image))completion; 30 | 31 | 32 | #pragma mark - Canceling 33 | /** 34 | * Cancel any rendering process 35 | */ 36 | - (void)cancelCurrentRendering; 37 | 38 | @end 39 | 40 | 41 | 42 | @interface VOXHistogramRenderer (Unavailable) 43 | 44 | 45 | - (instancetype)init NS_UNAVAILABLE; 46 | + (instancetype)new NS_UNAVAILABLE; 47 | 48 | @end -------------------------------------------------------------------------------- /Pod/Classes/Rendering/VOXHistogramRenderer.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 09.01.15. 3 | // Copyright (c) 2015 Alterplay. All rights reserved. 4 | // 5 | 6 | #import "VOXHistogramRenderer.h" 7 | #import "VOXHistogramRenderingOperation.h" 8 | #import "VOXHistogramRenderingConfiguration.h" 9 | 10 | 11 | 12 | @interface VOXHistogramRenderer () 13 | 14 | 15 | @property(nonatomic, strong) NSOperationQueue *renderingQueue; 16 | @property(nonatomic, strong) VOXHistogramRenderingConfiguration *renderingConfiguration; 17 | 18 | @end 19 | 20 | 21 | 22 | @implementation VOXHistogramRenderer 23 | 24 | 25 | #pragma mark - Init 26 | 27 | - (instancetype)initWithRenderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration 28 | { 29 | self = [super init]; 30 | if (self) { 31 | self.renderingConfiguration = renderingConfiguration; 32 | 33 | // queue setup 34 | self.renderingQueue = [NSOperationQueue new]; 35 | } 36 | return self; 37 | } 38 | 39 | + (instancetype)rendererWithRenderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration 40 | { 41 | return [[self alloc] initWithRenderingConfiguration:renderingConfiguration]; 42 | } 43 | 44 | #pragma mark - Rendering 45 | 46 | - (void)renderHistogramWithLevels:(NSArray *)levels 47 | completion:(void (^)(UIImage *image))completion 48 | { 49 | NSParameterAssert(levels); 50 | NSParameterAssert(completion); 51 | 52 | /* Cancel previous operation if any */ 53 | [self.renderingQueue cancelAllOperations]; 54 | 55 | /* Creating rendering operation */ 56 | VOXHistogramRenderingOperation *renderingOperation; 57 | renderingOperation = [VOXHistogramRenderingOperation operationWithLevels:levels 58 | renderingConfiguration:self.renderingConfiguration]; 59 | renderingOperation.completion = completion; 60 | 61 | /* Run operation on rendering queue */ 62 | [self.renderingQueue addOperation:renderingOperation]; 63 | } 64 | 65 | #pragma mark - Canceling 66 | 67 | - (void)cancelCurrentRendering 68 | { 69 | [self.renderingQueue cancelAllOperations]; 70 | } 71 | 72 | @end -------------------------------------------------------------------------------- /Pod/Classes/Rendering/VOXHistogramRenderingOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 09.01.15. 3 | // Copyright (c) 2015 Alterplay. All rights reserved. 4 | // 5 | 6 | #import 7 | #import 8 | 9 | @class VOXHistogramRenderingConfiguration; 10 | 11 | 12 | 13 | @interface VOXHistogramRenderingOperation : NSOperation 14 | 15 | 16 | #pragma mark - Completion 17 | /** 18 | * Block will be called when finished rendering 19 | */ 20 | @property(nonatomic, copy) void (^completion)(UIImage *image); 21 | 22 | #pragma mark - Rendered Image 23 | /** 24 | * Rendered image, nil until operation is finished 25 | */ 26 | @property(nonatomic, strong, readonly) UIImage *image; 27 | 28 | 29 | #pragma mark - Init 30 | - (instancetype)initWithLevels:(NSArray *)levels 31 | renderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration NS_DESIGNATED_INITIALIZER; 32 | + (instancetype)operationWithLevels:(NSArray *)levels 33 | renderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration; 34 | 35 | 36 | @end 37 | 38 | 39 | 40 | @interface VOXHistogramRenderingOperation (Unavailable) 41 | 42 | 43 | - (instancetype)init NS_UNAVAILABLE; 44 | + (instancetype)new NS_UNAVAILABLE; 45 | 46 | @end -------------------------------------------------------------------------------- /Pod/Classes/Rendering/VOXHistogramRenderingOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 09.01.15. 3 | // Copyright (c) 2015 Alterplay. All rights reserved. 4 | // 5 | 6 | #import "VOXHistogramRenderingOperation.h" 7 | #import "macros_blocks.h" 8 | #import "VOXHistogramRenderingConfiguration.h" 9 | 10 | 11 | 12 | @interface VOXHistogramRenderingOperation () 13 | 14 | 15 | @property(nonatomic, strong, readwrite) UIImage *image; 16 | @property(nonatomic, copy) NSArray *levels; 17 | @property(nonatomic, strong) VOXHistogramRenderingConfiguration *renderingConfiguration; 18 | 19 | @end 20 | 21 | 22 | 23 | @implementation VOXHistogramRenderingOperation 24 | 25 | 26 | #pragma mark - Init 27 | 28 | - (instancetype)initWithLevels:(NSArray *)levels 29 | renderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration 30 | { 31 | NSParameterAssert(levels); 32 | NSParameterAssert(renderingConfiguration); 33 | 34 | self = [super init]; 35 | if (self) { 36 | self.levels = levels; 37 | self.renderingConfiguration = renderingConfiguration; 38 | } 39 | return self; 40 | } 41 | 42 | + (instancetype)operationWithLevels:(NSArray *)levels 43 | renderingConfiguration:(VOXHistogramRenderingConfiguration *)renderingConfiguration 44 | { 45 | return [[self alloc] initWithLevels:levels renderingConfiguration:renderingConfiguration]; 46 | } 47 | 48 | #pragma mark - NSOperation 49 | 50 | - (void)main 51 | { 52 | if ([self isCancelled]) { 53 | return; 54 | } 55 | 56 | NSArray *levels = self.levels; 57 | UIImage *renderedImage = [self renderedHistogramWithLevels:levels]; 58 | 59 | if ([self isCancelled]) { 60 | return; 61 | } 62 | 63 | self.image = renderedImage; 64 | 65 | // call completion block with result 66 | main_queue_block(self.completion, self.image); 67 | } 68 | 69 | #pragma mark - Rendering 70 | 71 | - (UIImage *)renderedHistogramWithLevels:(NSArray *)levels 72 | { 73 | /* Get image size */ 74 | CGSize outputImageSize = self.renderingConfiguration.outputImageSize; 75 | 76 | /* Creating image context */ 77 | UIGraphicsBeginImageContextWithOptions(outputImageSize, NO, [self scale]); 78 | CGContextRef context = UIGraphicsGetCurrentContext(); 79 | 80 | /* Please, no antialiasing */ 81 | CGContextSetShouldAntialias(context, NO); 82 | 83 | [levels enumerateObjectsUsingBlock:^(NSNumber *levelNumber, NSUInteger idx, BOOL *stop) { 84 | /* Check operation is cancelled */ 85 | if ([self isCancelled]) { 86 | *stop = YES; 87 | return; 88 | } 89 | 90 | /* Get float from NSNumber */ 91 | CGFloat levelFloat = [levelNumber floatValue]; 92 | 93 | /* Calculate current peak offset */ 94 | CGFloat peakOffset = idx * ([self onePeakWidth] + [self marginWidth]); 95 | 96 | /* Draw every line for peak width */ 97 | for (int i = 0; i < [self linesCountInOnePeak]; i ++) { 98 | 99 | /* Calculate current line offset */ 100 | CGFloat lineOffset = peakOffset + i * [self lineMinimumWidth]; 101 | 102 | /* Get current line color */ 103 | UIColor *lineColor = self.renderingConfiguration.peaksColor; 104 | 105 | CGRect rect = CGRectMake(0.0f, 0.0f, outputImageSize.width, outputImageSize.height); 106 | 107 | /* Lets draw */ 108 | [self drawLineInContext:context 109 | inRect:rect 110 | withLeftOffset:lineOffset 111 | andWidth:[self lineMinimumWidth] 112 | andLevel:levelFloat 113 | andColor:lineColor]; 114 | } 115 | }]; 116 | 117 | /* Check operation is cancelled */ 118 | if ([self isCancelled]) { 119 | /* Context clean up */ 120 | UIGraphicsEndImageContext(); 121 | return nil; 122 | } 123 | 124 | /* Get result image from context */ 125 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 126 | 127 | /* Context clean up */ 128 | UIGraphicsEndImageContext(); 129 | 130 | /* Return image in current rendering mode */ 131 | return [image imageWithRenderingMode:self.renderingConfiguration.renderingMode]; 132 | } 133 | 134 | - (void)drawLineInContext:(CGContextRef)context 135 | inRect:(CGRect)rect 136 | withLeftOffset:(CGFloat)leftOffset 137 | andWidth:(CGFloat)width 138 | andLevel:(CGFloat)level 139 | andColor:(UIColor *)color 140 | { 141 | // Set line color 142 | CGContextSetStrokeColorWithColor(context, color.CGColor); 143 | 144 | // Set line width 145 | CGContextSetLineWidth(context, width); 146 | 147 | // Maybe this will make lines beautiful, but i'm not sure 148 | CGContextSetLineCap(context, kCGLineCapButt); 149 | 150 | // Get current rect height 151 | CGFloat rectHeight = CGRectGetHeight(rect); 152 | 153 | // start to draw line at bottom point 154 | CGContextMoveToPoint(context, leftOffset, rectHeight); 155 | 156 | // calculating line height for level 157 | CGFloat lineHeight = floorf(level * rectHeight); 158 | 159 | // drawing line with calculated height 160 | CGContextAddLineToPoint(context, leftOffset, rectHeight - lineHeight); 161 | 162 | // draw stroke 163 | CGContextStrokePath(context); 164 | } 165 | 166 | #pragma mark - Helpers 167 | 168 | - (CGFloat)lineMinimumWidth 169 | { 170 | return 1 / [self scale]; 171 | } 172 | 173 | - (CGFloat)onePeakWidth 174 | { 175 | return [self lineMinimumWidth] * self.renderingConfiguration.peakWidth; 176 | } 177 | 178 | - (CGFloat)marginWidth 179 | { 180 | return [self lineMinimumWidth] * self.renderingConfiguration.marginWidth; 181 | } 182 | 183 | - (NSUInteger)linesCountInOnePeak 184 | { 185 | return (NSUInteger) ([self onePeakWidth] / [self lineMinimumWidth]); 186 | } 187 | 188 | - (CGFloat)scale 189 | { 190 | return [UIScreen mainScreen].scale; 191 | } 192 | 193 | @end -------------------------------------------------------------------------------- /Pod/Classes/VOXHistogramControlView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/21/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | @class VOXHistogramControlView; 30 | @class VOXHistogramView; 31 | @class VOXProgressLineView; 32 | 33 | 34 | typedef NS_ENUM(NSUInteger, VOXHistogramControlViewTrackingMode) 35 | { 36 | VOXHistogramControlViewTrackingModeNone = 0, 37 | VOXHistogramControlViewTrackingModeTap, 38 | VOXHistogramControlViewTrackingModeLongTap 39 | }; 40 | 41 | 42 | 43 | @protocol VOXHistogramControlViewDelegate 44 | 45 | 46 | @optional 47 | 48 | /** 49 | * Called when histogram will be shown soon. 50 | */ 51 | - (void)histogramControlViewWillShowHistogram:(VOXHistogramControlView *)controlView; 52 | 53 | /** 54 | * Called right after histogram is showed. 55 | */ 56 | - (void)histogramControlViewDidShowHistogram:(VOXHistogramControlView *)controlView; 57 | 58 | /** 59 | * Called when histogram will be hidden soon. 60 | */ 61 | - (void)histogramControlViewWillHideHistogram:(VOXHistogramControlView *)controlView; 62 | 63 | /** 64 | * Called right after histogram is hidden. 65 | */ 66 | - (void)histogramControlViewDidHideHistogram:(VOXHistogramControlView *)controlView; 67 | 68 | /** 69 | * Called when user start tracking. 70 | */ 71 | - (void)histogramControlViewDidStartTracking:(VOXHistogramControlView *)controlView; 72 | 73 | /** 74 | * Called when progress changed even if tracking is not finished yet. 75 | */ 76 | - (void)histogramControlView:(VOXHistogramControlView *)controlView 77 | didChangeProgress:(CGFloat)progress; 78 | 79 | /** 80 | * Called when user did finish tracking. 81 | */ 82 | - (void) histogramControlView:(VOXHistogramControlView *)controlView 83 | didFinishTrackingWithProgress:(CGFloat)progress; 84 | 85 | /** 86 | * Called when user did change scrubbing speed. 87 | */ 88 | - (void)histogramControlView:(VOXHistogramControlView *)controlView 89 | didChangeScrubbingSpeed:(CGFloat)scrubbingSpeed; 90 | 91 | /** 92 | * Called when histogram rendering is about to start. 93 | */ 94 | - (void)histogramControlViewWillStartRendering:(VOXHistogramControlView *)controlView; 95 | 96 | /** 97 | * Called when histogram rendering finished. 98 | */ 99 | - (void)histogramControlViewDidFinishRendering:(VOXHistogramControlView *)controlView; 100 | 101 | @end 102 | 103 | 104 | 105 | @interface VOXHistogramControlView : UIView 106 | 107 | 108 | #pragma mark - Delegate 109 | @property(nonatomic, weak) id delegate; 110 | 111 | 112 | #pragma mark - Managed Views 113 | @property(nonatomic, weak, readonly) VOXHistogramView *histogramView; 114 | @property(nonatomic, weak, readonly) VOXProgressLineView *slider; 115 | 116 | 117 | #pragma mark - Inspectable Properties 118 | 119 | /** 120 | * Peaks colors setup 121 | */ 122 | @property(nonatomic, strong) IBInspectable UIColor *completeColor; 123 | @property(nonatomic, strong) IBInspectable UIColor *notCompleteColor; 124 | @property(nonatomic, strong) IBInspectable UIColor *downloadedColor; 125 | 126 | /** 127 | * Width of one peak in pixels (not points!) 128 | */ 129 | @property(nonatomic, assign) IBInspectable NSUInteger peakWidth; 130 | 131 | /** 132 | * Margin between two peaks in pixels (not points!) 133 | */ 134 | @property(nonatomic, assign) IBInspectable NSUInteger marginWidth; 135 | 136 | /** 137 | * Histogram view height. 138 | * 139 | * @default self.bounds.size.height 140 | */ 141 | @property(nonatomic, assign) IBInspectable CGFloat histogramHeight; 142 | 143 | /** 144 | * Height of VOXProgressLineView under histogram. 145 | * If 0.0f then slider will not be created. 146 | * 147 | * @default 0.0f 148 | */ 149 | @property(nonatomic, assign) IBInspectable CGFloat sliderHeight; 150 | 151 | /** 152 | * Use scrubbing or not 153 | * 154 | * @default YES 155 | */ 156 | @property(nonatomic, assign, readonly) IBInspectable BOOL useScrubbing; 157 | 158 | 159 | #pragma mark - Setup 160 | 161 | /** 162 | * Current tracking mode 163 | * 164 | * VOXHistogramControlViewTrackingModeNone - tracking will be off 165 | * VOXHistogramControlViewTrackingModeTap - tracking will start from tap 166 | * VOXHistogramControlViewTrackingModeLongTap - tracking will start from long tap 167 | * 168 | * @default VOXHistogramControlViewTrackingModeTap 169 | */ 170 | @property(nonatomic, assign) VOXHistogramControlViewTrackingMode trackingMode; 171 | 172 | 173 | #pragma mark - State 174 | 175 | /** 176 | * Array of NSNumbers representing histogram levels. 177 | * All values should be between @0.0 and @1.0. 178 | * 179 | * @discussion 180 | * If levels count more than histogram can display in current bounds then levels would be averaged. 181 | * This would be done on background thread. But then rendering process will take more time. 182 | * 183 | * If you do not want to do additional work while rendering histogram then you should always provide 184 | * exact count of levels that histogram can display. To know how much levels you need you should 185 | * use maximumSamplingRate property - it always shows how much levels do you need in current bounds. 186 | */ 187 | @property(nonatomic, copy) NSArray *levels; 188 | 189 | /** 190 | * Playback progress value. 191 | */ 192 | @property(nonatomic, assign) CGFloat playbackProgress; 193 | 194 | /** 195 | * Download progress value. 196 | */ 197 | @property(nonatomic, assign) CGFloat downloadProgress; 198 | 199 | /** 200 | * Returns YES if tracking began. 201 | */ 202 | @property(nonatomic, assign, readonly, getter=isTracking) BOOL tracking; 203 | 204 | /** 205 | * Returns YES if histogram currently presented. 206 | */ 207 | @property(nonatomic, assign, readonly) BOOL histogramPresented; 208 | 209 | /** 210 | * Return YES if currently animating histogram show/hide. 211 | */ 212 | @property(nonatomic, assign, readonly) BOOL animating; 213 | 214 | /** 215 | * Returns maximum count of samples that histogram can show in current bounds. 216 | * Calculated from peakWidth and marginWidth and bound.size.width. 217 | */ 218 | @property(nonatomic, assign, readonly) NSUInteger maximumSamplingRate; 219 | 220 | 221 | #pragma mark - Scrubbing 222 | 223 | /** 224 | * Returns current scrubbing speed. 225 | */ 226 | @property(nonatomic, assign, readonly) CGFloat scrubbingSpeed; 227 | 228 | /** 229 | * Array of NSNumbers representing scrubbing speeds for different zones. 230 | * 231 | * @example @[ @1.0f, @0.5f, @0.25f, @0.1f ] - this means first zone has 100% speed, 232 | * second zone 50%, and so on. 233 | */ 234 | @property(nonatomic, copy) NSArray *scrubbingSpeeds; 235 | 236 | /** 237 | * Array of NSNumbers representing zones when scrubbing speed changes. Every element of array 238 | * means distance by Y from user first touch where tracking began. 239 | * 240 | * @example @[ @0.0f, @50.0f, @100.0f, @150.0f ] - this means scrubbingSpeeds[0] acts 241 | * between 0 and 50pt distance from users touch by Y, scrubbingSpeeds[1] acts between 242 | * 50 and 100pt and so on. 243 | */ 244 | @property(nonatomic, copy) NSArray *scrubbingSpeedChangePositions; 245 | 246 | 247 | #pragma mark - Public 248 | 249 | /** 250 | * Show or hide histogram view. 251 | */ 252 | - (void)showHistogramViewAnimated:(BOOL)animated; 253 | - (void)hideHistogramViewAnimated:(BOOL)animated; 254 | 255 | /** 256 | * Will stop current histogram rendering if any. 257 | */ 258 | - (void)stopHistogramRendering; 259 | 260 | @end -------------------------------------------------------------------------------- /Pod/Classes/VOXHistogramControlView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/21/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "VOXHistogramControlView.h" 28 | #import "VOXHistogramView.h" 29 | #import "VOXProgressLineView.h" 30 | #import "VOXHistogramRenderer.h" 31 | #import "VOXHistogramRenderingConfiguration.h" 32 | #import "VOXHistogramLevelsConverter.h" 33 | #import "VOXHistogramAnimator.h" 34 | #import "UIView+Autolayout.h" 35 | #import "FrameAccessor.h" 36 | 37 | 38 | 39 | static NSUInteger const VOXHistogramControlViewDefaultPeakWidth = 3; 40 | static NSUInteger const VOXHistogramControlViewDefaultMarginWidth = 1; 41 | 42 | 43 | 44 | @interface VOXHistogramControlView () 45 | 46 | 47 | #pragma mark - Public 48 | @property(nonatomic, assign, readwrite, getter=isTracking) BOOL tracking; 49 | @property(nonatomic, assign, readwrite) CGFloat scrubbingSpeed; 50 | @property(nonatomic, assign, readwrite) IBInspectable BOOL useScrubbing; 51 | 52 | #pragma mark - Managed Views 53 | @property(nonatomic, weak, readwrite) VOXHistogramView *histogramView; 54 | @property(nonatomic, weak, readwrite) VOXProgressLineView *slider; 55 | 56 | #pragma mark - Helpers 57 | @property(assign, nonatomic) CGPoint beganTrackingLocation; 58 | @property(assign, nonatomic) CGFloat realPositionValue; 59 | @property(nonatomic, weak) UITouch *currentTouch; 60 | 61 | @property(nonatomic, strong) VOXHistogramRenderer *histogramRenderer; 62 | @property(nonatomic, strong) VOXHistogramAnimator *animator; 63 | @end 64 | 65 | 66 | 67 | @implementation VOXHistogramControlView 68 | 69 | 70 | #pragma mark - Accessors 71 | 72 | - (void)setCompleteColor:(UIColor *)completeColor 73 | { 74 | _completeColor = completeColor; 75 | self.histogramView.completeColor = completeColor; 76 | self.slider.completeColor = completeColor; 77 | } 78 | 79 | - (void)setNotCompleteColor:(UIColor *)notCompleteColor 80 | { 81 | _notCompleteColor = notCompleteColor; 82 | self.histogramView.notCompleteColor = notCompleteColor; 83 | self.slider.notCompleteColor = notCompleteColor; 84 | } 85 | 86 | - (void)setDownloadedColor:(UIColor *)downloadedColor 87 | { 88 | _downloadedColor = downloadedColor; 89 | self.histogramView.downloadedColor = downloadedColor; 90 | self.slider.downloadedColor = downloadedColor; 91 | } 92 | 93 | - (void)setLevels:(NSArray *)levels 94 | { 95 | _levels = [levels copy]; 96 | [self _renderHistogram]; 97 | } 98 | 99 | - (void)setPlaybackProgress:(CGFloat)playbackProgress 100 | { 101 | if (_playbackProgress == playbackProgress || self.isTracking) 102 | return; 103 | 104 | _playbackProgress = [self _normalizedValue:playbackProgress]; 105 | 106 | [self.slider updatePlaybackProgress:playbackProgress]; 107 | 108 | if (! self.animator.animating) { 109 | [self.histogramView updatePlaybackProgress:playbackProgress]; 110 | } 111 | } 112 | 113 | - (void)setDownloadProgress:(CGFloat)downloadProgress 114 | { 115 | if (_downloadProgress == downloadProgress) 116 | return; 117 | 118 | _downloadProgress = [self _normalizedDownloadProgressValue:downloadProgress]; 119 | 120 | [self.slider updateDownloadProgress:downloadProgress]; 121 | 122 | if (! self.animator.animating) { 123 | [self.histogramView updateDownloadProgress:downloadProgress]; 124 | } 125 | } 126 | 127 | - (BOOL)histogramPresented 128 | { 129 | return self.animator.histogramPresented; 130 | } 131 | 132 | - (BOOL)animating 133 | { 134 | return self.animator.animating; 135 | } 136 | 137 | #pragma mark - Init 138 | 139 | - (id)initWithCoder:(NSCoder *)coder 140 | { 141 | self = [super initWithCoder:coder]; 142 | if (self) { 143 | [self setupHistogramView]; 144 | [self setupDefaults]; 145 | } 146 | return self; 147 | } 148 | 149 | - (instancetype)initWithFrame:(CGRect)frame 150 | { 151 | self = [super initWithFrame:frame]; 152 | if (self) { 153 | [self setupHistogramView]; 154 | [self setupDefaults]; 155 | [self setup]; 156 | } 157 | return self; 158 | } 159 | 160 | - (void)awakeFromNib 161 | { 162 | [super awakeFromNib]; 163 | [self setup]; 164 | 165 | // we should set color to slider here because designable 166 | // properties are set between initWithCoder and awakeFromNib 167 | self.slider.completeColor = self.completeColor; 168 | self.slider.downloadedColor = self.downloadedColor; 169 | self.slider.notCompleteColor = self.notCompleteColor; 170 | } 171 | 172 | #pragma mark - Setup 173 | 174 | - (void)setupDefaults 175 | { 176 | /* No slider by default */ 177 | self.sliderHeight = 0.0f; 178 | 179 | /* Use scrubbing */ 180 | self.useScrubbing = YES; 181 | 182 | /* Histogram params */ 183 | self.peakWidth = VOXHistogramControlViewDefaultPeakWidth; 184 | self.marginWidth = VOXHistogramControlViewDefaultMarginWidth; 185 | 186 | /* Colors */ 187 | self.completeColor = [UIColor yellowColor]; 188 | self.downloadedColor = [UIColor lightGrayColor]; 189 | self.notCompleteColor = [UIColor darkGrayColor]; 190 | 191 | /* Scrubbing setup */ 192 | self.scrubbingSpeeds = [self _defaultScrubbingSpeeds]; 193 | self.scrubbingSpeedChangePositions = [self _defaultScrubbingSpeedChangePositions]; 194 | self.scrubbingSpeed = [self.scrubbingSpeeds[0] floatValue]; 195 | } 196 | 197 | - (void)setup 198 | { 199 | /* Setup managed views */ 200 | [self setupSliderIfNeeded]; 201 | [self setupViewsConstraints]; 202 | 203 | /* Create animator */ 204 | self.animator = [VOXHistogramAnimator animatorWithHistogramView:self.histogramView]; 205 | self.animator.delegate = self; 206 | 207 | /* Gesture recognizer setup */ 208 | [self setupGestureRecognizer]; 209 | } 210 | 211 | - (void)setupHistogramView 212 | { 213 | VOXHistogramView *histogramView = [VOXHistogramView autolayoutView]; 214 | [self addSubview:histogramView]; 215 | self.histogramView = histogramView; 216 | } 217 | 218 | - (void)setupSliderIfNeeded 219 | { 220 | if (self.sliderHeight > 0) { 221 | VOXProgressLineView *slider = [VOXProgressLineView autolayoutView]; 222 | [self addSubview:slider]; 223 | self.slider = slider; 224 | } 225 | } 226 | 227 | - (void)setupViewsConstraints 228 | { 229 | VOXHistogramView *histogramView = self.histogramView; 230 | 231 | NSDictionary *histogramBinding = NSDictionaryOfVariableBindings(histogramView); 232 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[histogramView]|" 233 | options:0 234 | metrics:nil 235 | views:histogramBinding]]; 236 | 237 | if (self.slider) { 238 | VOXProgressLineView *slider = self.slider; 239 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[slider]|" 240 | options:0 241 | metrics:nil 242 | views:NSDictionaryOfVariableBindings(slider)]]; 243 | NSString *format = [NSString stringWithFormat:@"V:[histogramView(%f)][slider(%f)]|", self.histogramHeight, self.sliderHeight]; 244 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:format 245 | options:0 246 | metrics:nil 247 | views:NSDictionaryOfVariableBindings(histogramView, slider)]]; 248 | } 249 | else { 250 | NSString *format = self.histogramHeight == 0 ? @"V:|[histogramView]|" : [NSString stringWithFormat:@"V:[histogramView(%f)]|", 251 | self.histogramHeight]; 252 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:format 253 | options:0 254 | metrics:nil 255 | views:histogramBinding]]; 256 | } 257 | } 258 | 259 | - (void)setupGestureRecognizer 260 | { 261 | UILongPressGestureRecognizer *longPressGestureRecognizer; 262 | longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self 263 | action:@selector(tapOccured:)]; 264 | longPressGestureRecognizer.delegate = self; 265 | CGFloat pressDuration = self.trackingMode == VOXHistogramControlViewTrackingModeLongTap ? 0.3f : 0.001f; 266 | longPressGestureRecognizer.minimumPressDuration = pressDuration; 267 | [self addGestureRecognizer:longPressGestureRecognizer]; 268 | } 269 | 270 | #pragma mark - Public 271 | 272 | - (void)showHistogramViewAnimated:(BOOL)animated 273 | { 274 | [self.animator showHistogramViewAnimated:animated]; 275 | } 276 | 277 | - (void)hideHistogramViewAnimated:(BOOL)animated 278 | { 279 | [self.animator hideHistogramViewAnimated:animated]; 280 | } 281 | 282 | - (void)stopHistogramRendering 283 | { 284 | [self.histogramRenderer cancelCurrentRendering]; 285 | self.histogramRenderer = nil; 286 | } 287 | 288 | #pragma mark - Gestures 289 | 290 | - (void)tapOccured:(UIGestureRecognizer *)sender 291 | { 292 | if (sender.state == UIGestureRecognizerStateBegan) { 293 | [self _notifyDelegateDidStartTracking]; 294 | } 295 | 296 | [self _updateValueForCurrentTouch]; 297 | 298 | if (sender.state == UIGestureRecognizerStateBegan) { 299 | self.tracking = YES; 300 | 301 | self.beganTrackingLocation = CGPointMake(self.playbackProgress * self.bounds.size.width, self.histogramView.bottom); 302 | self.realPositionValue = self.playbackProgress; 303 | } 304 | else if (sender.state == UIGestureRecognizerStateChanged) { 305 | if (self.useScrubbing) { 306 | [self _updateScrubbingSpeed]; 307 | } 308 | } 309 | else if (sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateEnded) { 310 | self.tracking = NO; 311 | self.currentTouch = nil; 312 | 313 | // set default scrubbing speed 314 | self.scrubbingSpeed = [self.scrubbingSpeeds[0] floatValue]; 315 | 316 | CGFloat playbackProgress = self.playbackProgress; 317 | [self _notifyDelegateDidFinishTrackingWithValue:playbackProgress]; 318 | } 319 | } 320 | 321 | #pragma mark - UIGestureRecognizerDelegate 322 | 323 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 324 | shouldReceiveTouch:(UITouch *)touch 325 | { 326 | self.currentTouch = touch; 327 | return YES; 328 | } 329 | 330 | #pragma mark - VOXHistogramAnimatorDelegate 331 | 332 | - (void)histogramAnimatorWillShowHistogram:(VOXHistogramAnimator *)controlView 333 | { 334 | [self _notifyDelegateWillShowHistogram]; 335 | } 336 | 337 | - (void)histogramAnimatorDidShowHistogram:(VOXHistogramAnimator *)controlView 338 | { 339 | [self _notifyDelegateDidShowHistogram]; 340 | } 341 | 342 | - (void)histogramAnimatorWillHideHistogram:(VOXHistogramAnimator *)controlView 343 | { 344 | [self _notifyDelegateWillHideHistogram]; 345 | } 346 | 347 | - (void)histogramAnimatorDidHideHistogram:(VOXHistogramAnimator *)controlView 348 | { 349 | [self _notifyDelegateDidHideHistogram]; 350 | } 351 | 352 | #pragma mark - Helpers 353 | 354 | - (void)_renderHistogram 355 | { 356 | /* Cancel previous rendering */ 357 | if (self.histogramRenderer) { 358 | [self.histogramRenderer cancelCurrentRendering]; 359 | } 360 | 361 | /* Notify delegate */ 362 | [self _notifyDelegateWillStartRendering]; 363 | 364 | /* Setup levels converter */ 365 | VOXHistogramLevelsConverter *converter = [VOXHistogramLevelsConverter new]; 366 | [converter updateLevels:self.levels]; 367 | 368 | /* Creating rendering configuration */ 369 | VOXHistogramRenderingConfiguration *renderingConfiguration = [VOXHistogramRenderingConfiguration new]; 370 | renderingConfiguration.outputImageSize = self.histogramView.bounds.size; 371 | renderingConfiguration.renderingMode = UIImageRenderingModeAlwaysTemplate; 372 | renderingConfiguration.peaksColor = [UIColor whiteColor]; 373 | renderingConfiguration.peakWidth = self.peakWidth; 374 | renderingConfiguration.marginWidth = self.marginWidth; 375 | 376 | /* Calculate number of levels that histogram can display in current bounds */ 377 | NSUInteger samplingRate = [self _samplingRateForHistogramWidth:CGRectGetWidth(self.histogramView.bounds) 378 | peakWidth:self.peakWidth 379 | marginWidth:self.marginWidth]; 380 | 381 | /* Creating histogram renderer */ 382 | self.histogramRenderer = [VOXHistogramRenderer rendererWithRenderingConfiguration:renderingConfiguration]; 383 | 384 | /* Rendering histogram image */ 385 | [converter calculateLevelsForSamplingRate:samplingRate completion:^(NSArray *levelsResampled) { 386 | [self.histogramRenderer renderHistogramWithLevels:levelsResampled completion:^(UIImage *image) { 387 | self.histogramView.image = image; 388 | 389 | /* Notify delegate */ 390 | [self _notifyDelegateDidFinishRendering]; 391 | }]; 392 | }]; 393 | } 394 | 395 | - (void)_updateValueForCurrentTouch 396 | { 397 | /* Get touch params */ 398 | CGPoint previousLocation = [self.currentTouch previousLocationInView:self]; 399 | CGPoint currentLocation = [self.currentTouch locationInView:self]; 400 | 401 | CGFloat trackingOffset = currentLocation.x - previousLocation.x; 402 | CGFloat controlViewWidth = CGRectGetWidth(self.bounds); 403 | 404 | self.realPositionValue = self.realPositionValue + (trackingOffset / controlViewWidth); 405 | 406 | CGFloat valueAdjustment = self.scrubbingSpeed * (trackingOffset / controlViewWidth); 407 | 408 | CGFloat thumbAdjustment = 0.0f; 409 | 410 | /* Vertical progress adjustment - when user moves finger down closer to histogram we should also adjust progress */ 411 | if (((self.beganTrackingLocation.y < currentLocation.y) && (currentLocation.y < previousLocation.y)) || 412 | ((self.beganTrackingLocation.y > currentLocation.y) && (currentLocation.y > previousLocation.y))) { 413 | // We are getting closer to the slider, go closer to the real location 414 | thumbAdjustment = (self.realPositionValue - self.playbackProgress) / (1 + fabs(currentLocation.y - self.beganTrackingLocation.y)); 415 | } 416 | 417 | if ((trackingOffset == 0 && (currentLocation.y - previousLocation.y) == 0) || ! self.useScrubbing) { 418 | _playbackProgress = currentLocation.x / controlViewWidth; 419 | } 420 | else { 421 | _playbackProgress += valueAdjustment + thumbAdjustment; // should not call setter here 422 | } 423 | 424 | [self.slider updatePlaybackProgress:self.playbackProgress]; 425 | [self.histogramView updatePlaybackProgress:self.playbackProgress]; 426 | 427 | [self _notifyDelegateDidChangePlaybackProgress:self.playbackProgress]; 428 | } 429 | 430 | - (void)_updateScrubbingSpeed 431 | { 432 | CGPoint touchLocation = [self.currentTouch locationInView:self]; 433 | CGFloat verticalOffset = ABS(touchLocation.y - self.beganTrackingLocation.y); 434 | NSUInteger scrubbingSpeedChangePosIndex = [self _indexOfLowerScrubbingSpeed:self.scrubbingSpeedChangePositions 435 | forOffset:verticalOffset]; 436 | if (scrubbingSpeedChangePosIndex == NSNotFound) { 437 | scrubbingSpeedChangePosIndex = [self.scrubbingSpeeds count]; 438 | } 439 | 440 | CGFloat scrubbingSpeed = [self.scrubbingSpeeds[scrubbingSpeedChangePosIndex - 1] floatValue]; 441 | 442 | if (scrubbingSpeed != self.scrubbingSpeed) { 443 | self.scrubbingSpeed = scrubbingSpeed; 444 | [self _notifyDelegateDidChangeScrubbingSpeed:scrubbingSpeed]; 445 | } 446 | } 447 | 448 | - (NSArray *)_defaultScrubbingSpeeds 449 | { 450 | return @[ @1.0f, @0.5f, @0.25f, @0.1f ]; 451 | } 452 | 453 | - (NSArray *)_defaultScrubbingSpeedChangePositions 454 | { 455 | return @[ @0.0f, @50.0f, @100.0f, @150.0f ]; 456 | } 457 | 458 | // Return the lowest index in the array of numbers passed in scrubbingSpeedPositions 459 | // whose value is smaller than verticalOffset. 460 | - (NSUInteger)_indexOfLowerScrubbingSpeed:(NSArray *)scrubbingSpeedPositions 461 | forOffset:(CGFloat)verticalOffset 462 | { 463 | for (NSUInteger i = 0; i < [scrubbingSpeedPositions count]; i ++) { 464 | NSNumber *scrubbingSpeedOffset = scrubbingSpeedPositions[i]; 465 | if (verticalOffset < [scrubbingSpeedOffset floatValue]) { 466 | return i; 467 | } 468 | } 469 | return NSNotFound; 470 | } 471 | 472 | - (NSUInteger)_samplingRateForHistogramWidth:(CGFloat)histogramWidth 473 | peakWidth:(CGFloat)peakWidth 474 | marginWidth:(CGFloat)marginWidth 475 | { 476 | CGFloat scale = [UIScreen mainScreen].scale; 477 | return (NSUInteger) ceilf((histogramWidth / (peakWidth + marginWidth)) * scale); 478 | } 479 | 480 | - (CGFloat)_normalizedValue:(CGFloat)value 481 | { 482 | return MAX(MIN(value, 1), 0); 483 | } 484 | 485 | - (CGFloat)_normalizedDownloadProgressValue:(CGFloat)downloadProgressValue 486 | { 487 | return MAX(MIN(downloadProgressValue, 1), self.playbackProgress); 488 | } 489 | 490 | #pragma mark - Delegate Notifications 491 | 492 | - (void)_notifyDelegateWillStartRendering 493 | { 494 | if ([self.delegate respondsToSelector:@selector(histogramControlViewWillStartRendering:)]) { 495 | [self.delegate histogramControlViewWillStartRendering:self]; 496 | } 497 | } 498 | 499 | - (void)_notifyDelegateDidFinishRendering 500 | { 501 | if ([self.delegate respondsToSelector:@selector(histogramControlViewDidFinishRendering:)]) { 502 | [self.delegate histogramControlViewDidFinishRendering:self]; 503 | } 504 | } 505 | 506 | - (void)_notifyDelegateDidStartTracking 507 | { 508 | if ([self.delegate respondsToSelector:@selector(histogramControlViewDidStartTracking:)]) { 509 | [self.delegate histogramControlViewDidStartTracking:self]; 510 | } 511 | } 512 | 513 | - (void)_notifyDelegateDidFinishTrackingWithValue:(CGFloat)playbackProgress 514 | { 515 | if ([self.delegate respondsToSelector:@selector(histogramControlView:didFinishTrackingWithProgress:)]) { 516 | [self.delegate histogramControlView:self 517 | didFinishTrackingWithProgress:playbackProgress]; 518 | } 519 | } 520 | 521 | - (void)_notifyDelegateDidChangeScrubbingSpeed:(CGFloat)scrubbingSpeed 522 | { 523 | if ([self.delegate respondsToSelector:@selector(histogramControlView:didChangeScrubbingSpeed:)]) { 524 | [self.delegate histogramControlView:self 525 | didChangeScrubbingSpeed:scrubbingSpeed]; 526 | } 527 | } 528 | 529 | - (void)_notifyDelegateWillShowHistogram 530 | { 531 | if ([self.delegate respondsToSelector:@selector(histogramControlViewWillShowHistogram:)]) { 532 | [self.delegate histogramControlViewWillShowHistogram:self]; 533 | } 534 | } 535 | 536 | - (void)_notifyDelegateDidShowHistogram 537 | { 538 | if ([self.delegate respondsToSelector:@selector(histogramControlViewDidShowHistogram:)]) { 539 | [self.delegate histogramControlViewDidShowHistogram:self]; 540 | } 541 | } 542 | 543 | - (void)_notifyDelegateWillHideHistogram 544 | { 545 | if ([self.delegate respondsToSelector:@selector(histogramControlViewWillHideHistogram:)]) { 546 | [self.delegate histogramControlViewWillHideHistogram:self]; 547 | } 548 | } 549 | 550 | - (void)_notifyDelegateDidHideHistogram 551 | { 552 | if ([self.delegate respondsToSelector:@selector(histogramControlViewDidHideHistogram:)]) { 553 | [self.delegate histogramControlViewDidHideHistogram:self]; 554 | } 555 | } 556 | 557 | - (void)_notifyDelegateDidChangePlaybackProgress:(CGFloat)playbackProgress 558 | { 559 | if ([self.delegate respondsToSelector:@selector(histogramControlView:didChangeProgress:)]) { 560 | [self.delegate histogramControlView:self 561 | didChangeProgress:playbackProgress]; 562 | } 563 | } 564 | 565 | @end -------------------------------------------------------------------------------- /Pod/Classes/VOXHistogramView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/8/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | 30 | 31 | @interface VOXHistogramView : UIView 32 | 33 | /** 34 | * Colors setup 35 | */ 36 | @property(nonatomic, strong) IBInspectable UIColor *completeColor; 37 | @property(nonatomic, strong) IBInspectable UIColor *notCompleteColor; 38 | @property(nonatomic, strong) IBInspectable UIColor *downloadedColor; 39 | 40 | /** 41 | * Histogram image 42 | */ 43 | @property(nonatomic, strong) UIImage *image; 44 | 45 | /** 46 | * Update current playback progress from 0.0f to 1.0f 47 | */ 48 | - (void)updatePlaybackProgress:(CGFloat)playbackProgress; 49 | 50 | /** 51 | * Update current download progress from 0.0f to 1.0f 52 | */ 53 | - (void)updateDownloadProgress:(CGFloat)downloadProgress; 54 | 55 | @end -------------------------------------------------------------------------------- /Pod/Classes/VOXHistogramView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nickolay Sheika on 10/8/14. 3 | // Copyright (c) 2014 Coppertino Inc. All rights reserved. (http://coppertino.com/) 4 | // 5 | // VOX, VOX Player, LOOP for VOX are registered trademarks of Coppertino Inc in US. 6 | // Coppertino Inc. 910 Foulk Road, Suite 201, Wilmington, County of New Castle, DE, 19803, USA. 7 | // Contact phone: +1 (888) 765-7069 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | 28 | #import "VOXHistogramView.h" 29 | #import "FrameAccessor.h" 30 | 31 | 32 | @interface VOXHistogramView () 33 | 34 | 35 | @property(nonatomic, assign) CGFloat playbackProgress; 36 | @property(nonatomic, assign) CGFloat downloadProgress; 37 | 38 | @property(nonatomic, weak) UIImageView *completeImageView; 39 | @property(nonatomic, weak) UIImageView *notCompleteImageView; 40 | @property(nonatomic, weak) UIImageView *downloadedImageView; 41 | 42 | @end 43 | 44 | 45 | 46 | @implementation VOXHistogramView 47 | 48 | 49 | #pragma mark - Accessors 50 | 51 | - (void)setCompleteColor:(UIColor *)completeColor 52 | { 53 | _completeColor = completeColor; 54 | self.completeImageView.tintColor = completeColor; 55 | } 56 | 57 | - (void)setNotCompleteColor:(UIColor *)notCompleteColor 58 | { 59 | _notCompleteColor = notCompleteColor; 60 | self.notCompleteImageView.tintColor = notCompleteColor; 61 | } 62 | 63 | - (void)setDownloadedColor:(UIColor *)downloadedColor 64 | { 65 | _downloadedColor = downloadedColor; 66 | self.downloadedImageView.tintColor = downloadedColor; 67 | } 68 | 69 | #pragma mark - Init 70 | 71 | - (instancetype)initWithFrame:(CGRect)frame 72 | { 73 | self = [super initWithFrame:frame]; 74 | if (self) { 75 | [self setup]; 76 | } 77 | return self; 78 | } 79 | 80 | - (instancetype)initWithCoder:(NSCoder *)coder 81 | { 82 | self = [super initWithCoder:coder]; 83 | if (self) { 84 | [self setup]; 85 | } 86 | return self; 87 | } 88 | 89 | - (instancetype)init 90 | { 91 | return [self initWithFrame:CGRectZero]; 92 | } 93 | 94 | #pragma mark - Layout 95 | 96 | - (void)layoutSubviews 97 | { 98 | [super layoutSubviews]; 99 | 100 | self.notCompleteImageView.frame = self.bounds; 101 | self.downloadedImageView.frame = self.bounds; 102 | self.completeImageView.frame = self.bounds; 103 | 104 | CGFloat currentWidth = CGRectGetWidth(self.bounds); 105 | self.completeImageView.width = currentWidth * self.playbackProgress; 106 | self.downloadedImageView.width = currentWidth * self.downloadProgress; 107 | } 108 | 109 | #pragma mark - Setup 110 | 111 | - (void)setup 112 | { 113 | self.notCompleteImageView = [self _buildImageView]; 114 | self.downloadedImageView = [self _buildImageView]; 115 | self.completeImageView = [self _buildImageView]; 116 | } 117 | 118 | - (UIImageView *)_buildImageView 119 | { 120 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 121 | imageView.clipsToBounds = YES; 122 | imageView.contentMode = UIViewContentModeLeft; 123 | [self addSubview:imageView]; 124 | return imageView; 125 | } 126 | 127 | #pragma mark - Accessors 128 | 129 | - (void)setImage:(UIImage *)image 130 | { 131 | if ([_image isEqual:image]) 132 | return; 133 | 134 | _image = image; 135 | 136 | self.completeImageView.image = image; 137 | self.notCompleteImageView.image = image; 138 | self.downloadedImageView.image = image; 139 | 140 | [self setNeedsLayout]; 141 | } 142 | 143 | #pragma mark - Public 144 | 145 | - (void)updatePlaybackProgress:(CGFloat)playbackProgress 146 | { 147 | self.playbackProgress = [self _normalizedValue:playbackProgress]; 148 | [self setNeedsLayout]; 149 | } 150 | 151 | - (void)updateDownloadProgress:(CGFloat)downloadProgress 152 | { 153 | self.downloadProgress = [self _normalizedDownloadProgressValue:downloadProgress]; 154 | [self setNeedsLayout]; 155 | } 156 | 157 | #pragma mark - Helpers 158 | 159 | - (CGFloat)_normalizedValue:(CGFloat)value 160 | { 161 | return MAX(MIN(value, 1), 0); 162 | } 163 | 164 | - (CGFloat)_normalizedDownloadProgressValue:(CGFloat)downloadProgressValue 165 | { 166 | return MAX(MIN(downloadProgressValue, 1), self.playbackProgress); 167 | } 168 | 169 | @end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #VOXHistogramView [![Build Status](https://travis-ci.org/Coppertino/VOXHistogramView.svg?branch=master)](https://travis-ci.org/Coppertino/VOXHistogramView) [![Version](https://img.shields.io/badge/version-0.1.0-cacaca.svg)](https://github.com/Coppertino/VOXHistogramView) [![Platform](https://img.shields.io/badge/platform-ios-blue.svg)](https://github.com/Coppertino/VOXHistogramView) 2 | 3 | **The best way to display histogram in your project. Free Software, Hell Yeah!** 4 | 5 | This software is used in our [VOX Player](https://itunes.apple.com/us/app/vox-player/id916215494). 6 | 7 | ![Demo](https://github.com/Coppertino/VOXHistogramView/blob/master/Gif/demo.gif "Demo") 8 | 9 | 10 | ## Usage 11 | 12 | There is two ways how you can use our software. 13 | 14 | ####1. VOXHistogramControlView 15 | 16 | This is a wrapper view over the entire histogram rendering process and playback control. 17 | 18 | - Handles users touches and tells delegate about all events. 19 | - Scrubbing speed support for precise control over audio track rewind. 20 | - Can animate histogram show/hide. 21 | - Controls playback and download progress. 22 | - Controls all histogram rendering process. 23 | - Can display slider view at the bottom of histogram. 24 | 25 | VOXHistogramControlView has full support for autolayout, can be instantiated from storyboard and many params can be setup by IBInspectable properties. 26 | 27 | This is the way we use histogram in our VOX Player project. 28 | 29 | 30 | ```objc 31 | 32 | CGRect frame = /* Build frame… */ 33 | VOXHistogramControlView *histogramControlView = [[VOXHistogramControlView alloc] initWithFrame:frame]; 34 | histogramControlView.delegate = self; 35 | 36 | NSArray *levels = /* Get levels from API or from player. It should be NSArray of NSNumbers from @0.0 to @1.0. */ 37 | histogramControlView.levels = levels; 38 | ``` 39 | 40 | ####2. Plain VOXHistogramView. 41 | 42 | If VOXHistogramControlView do not suits your needs you can use all components separately. 43 | 44 | Lets describe them: 45 | 46 | #####VOXHistogramView 47 | 48 | Allows you to display rendered histogram image and provides control over playback progress and download progress. It supports autolayout and can be instantiated from storyboard. 49 | 50 | ```objc 51 | CGRect frame = /* Setup histogram frame */ 52 | VOXHistogramView *histogramView = [[VOXHistogramView alloc] initWithFrame:frame]; 53 | 54 | UIImage *image = /* Render histogram image */ 55 | histogramView.image = image; 56 | ``` 57 | 58 | #####VOXHistogramRenderer 59 | 60 | This is main hard worker - it is used to render histogram image from array of levels. Rendering goes in background thread and not blocking the UI. 61 | 62 | ```objc 63 | 64 | VOXHistogramRenderingConfiguration *renderingConfiguration = /* Setup rendering configuration… */ 65 | 66 | VOXHistogramRenderer *renderer = [VOXHistogramRenderer rendererWithRenderingConfiguration:renderingConfiguration]; 67 | 68 | NSArray *levels = /* Get levels from API or from player. It should be NSArray of NSNumbers from @0.0 to @1.0. */ 69 | 70 | [renderer renderHistogramWithLevels:levels completion:^(UIImage *image) { 71 | /* Use histogram image */ 72 | }]; 73 | ``` 74 | 75 | #####VOXHistogramLevelsConverter 76 | 77 | This class allows you to convert levels array in background. For example you have received 1000 levels from API but you need only 300 to display VOXHistogramView in current bounds. So you need to convert those levels by averaging them. This is what VOXHistogramLevelsConverter was created for. 78 | 79 | ```objc 80 | VOXHistogramLevelsConverter *converter = [VOXHistogramLevelsConverter new]; 81 | 82 | NSArray *levels = /* Get levels from API or from player… */ 83 | [converter updateLevels:levels]; 84 | 85 | 86 | NSUInteger samplingRate = /* Calculate number of levels that histogram can display in current bounds */ 87 | 88 | /* Convert levels array to sampling rate and render histogram image */ 89 | [converter calculateLevelsForSamplingRate:samplingRate completion:^(NSArray *levelsResampled) { 90 | /* Use resampled levels to render histogram image */ 91 | }]; 92 | 93 | ``` 94 | 95 | ###Levels for audio track 96 | 97 | To use our library you should provide array of audio track levels. This is simple NSArray of NSNumbers from @0.0 to @1.0 representing sound level for moment in time. You can get those levels from your audio engine (like BASS) or from API (like Soundcloud). 98 | 99 | How many levels do you need? 100 | 101 | It depends from many parameters like width of one peak, margin between peaks, current VOXHistogramView bounds, device screen scale. For convenience you can use maximumSamplingRate property in VOXHistogramControlView or you should calculate this by yourself if you are using plain VOXHistogramView (take a look in example project). 102 | 103 | 104 | 105 | ## Roadmap 106 | 107 | 1. A lot more unit tests. 108 | 2. Separate pod for VOXHistogramControlView. 109 | 3. Speed improvements in VOXHistogramLevelsConverter. 110 | 111 | ## Example 112 | 113 | To run the example project, clone the repo, and run pod install from the Example directory first. 114 | 115 | ## Requirements 116 | 117 | - iOS 7.1 and higher 118 | - ARC 119 | 120 | ## Installation 121 | 122 | VOXHistogramView is available through [CocoaPods](http://cocoapods.org). To install 123 | it, simply add the following line to your Podfile: 124 | 125 | ```ruby 126 | pod "VOXHistogramView" 127 | ``` 128 | 129 | ## Author 130 | 131 | Nickolay Sheika, hawk.ukr@gmail.com 132 | 133 | ## License 134 | 135 | VOXHistogramView is available under the MIT license. See the LICENSE file for more info. 136 | **VOX**, **VOX Player**, **LOOP for VOX** are registered trademarks of Coppertino Inc in US. 137 | 138 | -------------------------------------------------------------------------------- /VOXHistogramView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "VOXHistogramView" 3 | s.version = "0.1.0" 4 | s.summary = "The best way to display histogram in your project." 5 | s.homepage = "https://github.com/Coppertino/VOXHistogramView" 6 | s.license = 'MIT' 7 | s.author = { "Nickolay Sheika" => "hawk.ukr@gmail.com" } 8 | s.source = { :git => "https://github.com/Coppertino/VOXHistogramView.git", :tag => s.version.to_s } 9 | 10 | s.platform = :ios, '7.1' 11 | s.requires_arc = true 12 | 13 | s.source_files = 'Pod/Classes/**/*' 14 | 15 | s.dependency 'macros_blocks', '0.0.3' 16 | s.dependency 'FrameAccessor', '2.0' 17 | end 18 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------