├── .gitignore ├── AudioArmada.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── AudioArmada.xcscheme └── xcuserdata │ └── corey.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── AudioArmada.xcworkspace ├── contents.xcworkspacedata └── xcuserdata │ └── corey.xcuserdatad │ └── xcdebugger │ └── Breakpoints_v2.xcbkptlist ├── AudioArmada ├── AudioArmada.h ├── Classes │ ├── WaveformRolling.swift │ └── WaveformZoomable.swift ├── Extensions │ ├── CGPoint+Operators.swift │ └── UIView+Normalize.swift ├── Info.plist └── Utilities │ └── AAMath.swift ├── AudioArmadaExamples ├── AudioArmadaExamples.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcuserdata │ │ └── corey.xcuserdatad │ │ └── xcschemes │ │ ├── AudioArmadaExamples.xcscheme │ │ └── xcschememanagement.plist ├── AudioArmadaExamples │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Audio Samples │ │ ├── Beat9.mp3 │ │ ├── Divergence.wav │ │ └── drumLoop.wav │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── Source │ │ ├── AppDelegate.swift │ │ ├── ExampleViewController.swift │ │ ├── ExamplesListViewController.swift │ │ ├── WaveformRollingView.swift │ │ ├── WaveformRollingViewController.swift │ │ ├── WaveformZoomableView.swift │ │ └── WaveformZoomableViewController.swift ├── Cartfile └── Cartfile.resolved ├── LICENSE ├── images ├── waveform_rolling.gif └── waveform_zoomable.png └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | Carthage -------------------------------------------------------------------------------- /AudioArmada.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0499F5791E8EF9B30003611B /* AudioArmada.h in Headers */ = {isa = PBXBuildFile; fileRef = 0499F5771E8EF9B30003611B /* AudioArmada.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 0499F5C11E8EFC140003611B /* WaveformZoomable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0499F5C01E8EFC140003611B /* WaveformZoomable.swift */; }; 12 | 04FBAEE81E930BD8003D123F /* AAMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBAEE71E930BD8003D123F /* AAMath.swift */; }; 13 | 04FBAEEA1E930C7A003D123F /* CGPoint+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBAEE91E930C7A003D123F /* CGPoint+Operators.swift */; }; 14 | 04FBAEEC1E930F91003D123F /* UIView+Normalize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBAEEB1E930F91003D123F /* UIView+Normalize.swift */; }; 15 | 04FE9ACD1E95FA8300DEC4D4 /* WaveformRolling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FE9ACC1E95FA8300DEC4D4 /* WaveformRolling.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 0499F5741E8EF9B20003611B /* AudioArmada.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AudioArmada.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 0499F5771E8EF9B30003611B /* AudioArmada.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioArmada.h; sourceTree = ""; }; 21 | 0499F5781E8EF9B30003611B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 0499F5C01E8EFC140003611B /* WaveformZoomable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WaveformZoomable.swift; path = Classes/WaveformZoomable.swift; sourceTree = ""; }; 23 | 04FBAEE71E930BD8003D123F /* AAMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AAMath.swift; path = Utilities/AAMath.swift; sourceTree = ""; }; 24 | 04FBAEE91E930C7A003D123F /* CGPoint+Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CGPoint+Operators.swift"; path = "Extensions/CGPoint+Operators.swift"; sourceTree = ""; }; 25 | 04FBAEEB1E930F91003D123F /* UIView+Normalize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Normalize.swift"; path = "Extensions/UIView+Normalize.swift"; sourceTree = ""; }; 26 | 04FE9ACC1E95FA8300DEC4D4 /* WaveformRolling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WaveformRolling.swift; path = Classes/WaveformRolling.swift; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 0499F5701E8EF9B20003611B /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | 0499F56A1E8EF9B20003611B = { 41 | isa = PBXGroup; 42 | children = ( 43 | 0499F5761E8EF9B30003611B /* Source */, 44 | 0499F5751E8EF9B20003611B /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 0499F5751E8EF9B20003611B /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 0499F5741E8EF9B20003611B /* AudioArmada.framework */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 0499F5761E8EF9B30003611B /* Source */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 0499F5771E8EF9B30003611B /* AudioArmada.h */, 60 | 0499F5781E8EF9B30003611B /* Info.plist */, 61 | 0499F5C21E8EFC1A0003611B /* Classes */, 62 | 04FBAEE61E930BB1003D123F /* Utilities */, 63 | 04FBAEE31E930AFF003D123F /* Extensions */, 64 | ); 65 | name = Source; 66 | path = AudioArmada; 67 | sourceTree = ""; 68 | }; 69 | 0499F5C21E8EFC1A0003611B /* Classes */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 0499F5C01E8EFC140003611B /* WaveformZoomable.swift */, 73 | 04FE9ACC1E95FA8300DEC4D4 /* WaveformRolling.swift */, 74 | ); 75 | name = Classes; 76 | sourceTree = ""; 77 | }; 78 | 04FBAEE31E930AFF003D123F /* Extensions */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 04FBAEE91E930C7A003D123F /* CGPoint+Operators.swift */, 82 | 04FBAEEB1E930F91003D123F /* UIView+Normalize.swift */, 83 | ); 84 | name = Extensions; 85 | sourceTree = ""; 86 | }; 87 | 04FBAEE61E930BB1003D123F /* Utilities */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 04FBAEE71E930BD8003D123F /* AAMath.swift */, 91 | ); 92 | name = Utilities; 93 | sourceTree = ""; 94 | }; 95 | /* End PBXGroup section */ 96 | 97 | /* Begin PBXHeadersBuildPhase section */ 98 | 0499F5711E8EF9B20003611B /* Headers */ = { 99 | isa = PBXHeadersBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | 0499F5791E8EF9B30003611B /* AudioArmada.h in Headers */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXHeadersBuildPhase section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | 0499F5731E8EF9B20003611B /* AudioArmada */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = 0499F57C1E8EF9B30003611B /* Build configuration list for PBXNativeTarget "AudioArmada" */; 112 | buildPhases = ( 113 | 0499F56F1E8EF9B20003611B /* Sources */, 114 | 0499F5701E8EF9B20003611B /* Frameworks */, 115 | 0499F5711E8EF9B20003611B /* Headers */, 116 | 0499F5721E8EF9B20003611B /* Resources */, 117 | ); 118 | buildRules = ( 119 | ); 120 | dependencies = ( 121 | ); 122 | name = AudioArmada; 123 | productName = AudioArmada; 124 | productReference = 0499F5741E8EF9B20003611B /* AudioArmada.framework */; 125 | productType = "com.apple.product-type.framework"; 126 | }; 127 | /* End PBXNativeTarget section */ 128 | 129 | /* Begin PBXProject section */ 130 | 0499F56B1E8EF9B20003611B /* Project object */ = { 131 | isa = PBXProject; 132 | attributes = { 133 | LastUpgradeCheck = 0820; 134 | ORGANIZATIONNAME = "Corey Walo"; 135 | TargetAttributes = { 136 | 0499F5731E8EF9B20003611B = { 137 | CreatedOnToolsVersion = 8.2; 138 | DevelopmentTeam = TGW6PA8S8E; 139 | LastSwiftMigration = 0820; 140 | ProvisioningStyle = Automatic; 141 | }; 142 | }; 143 | }; 144 | buildConfigurationList = 0499F56E1E8EF9B20003611B /* Build configuration list for PBXProject "AudioArmada" */; 145 | compatibilityVersion = "Xcode 3.2"; 146 | developmentRegion = English; 147 | hasScannedForEncodings = 0; 148 | knownRegions = ( 149 | en, 150 | ); 151 | mainGroup = 0499F56A1E8EF9B20003611B; 152 | productRefGroup = 0499F5751E8EF9B20003611B /* Products */; 153 | projectDirPath = ""; 154 | projectRoot = ""; 155 | targets = ( 156 | 0499F5731E8EF9B20003611B /* AudioArmada */, 157 | ); 158 | }; 159 | /* End PBXProject section */ 160 | 161 | /* Begin PBXResourcesBuildPhase section */ 162 | 0499F5721E8EF9B20003611B /* Resources */ = { 163 | isa = PBXResourcesBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXSourcesBuildPhase section */ 172 | 0499F56F1E8EF9B20003611B /* Sources */ = { 173 | isa = PBXSourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 0499F5C11E8EFC140003611B /* WaveformZoomable.swift in Sources */, 177 | 04FBAEE81E930BD8003D123F /* AAMath.swift in Sources */, 178 | 04FE9ACD1E95FA8300DEC4D4 /* WaveformRolling.swift in Sources */, 179 | 04FBAEEC1E930F91003D123F /* UIView+Normalize.swift in Sources */, 180 | 04FBAEEA1E930C7A003D123F /* CGPoint+Operators.swift in Sources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXSourcesBuildPhase section */ 185 | 186 | /* Begin XCBuildConfiguration section */ 187 | 0499F57A1E8EF9B30003611B /* Debug */ = { 188 | isa = XCBuildConfiguration; 189 | buildSettings = { 190 | ALWAYS_SEARCH_USER_PATHS = NO; 191 | CLANG_ANALYZER_NONNULL = YES; 192 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 193 | CLANG_CXX_LIBRARY = "libc++"; 194 | CLANG_ENABLE_MODULES = YES; 195 | CLANG_ENABLE_OBJC_ARC = YES; 196 | CLANG_WARN_BOOL_CONVERSION = YES; 197 | CLANG_WARN_CONSTANT_CONVERSION = YES; 198 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 199 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 200 | CLANG_WARN_EMPTY_BODY = YES; 201 | CLANG_WARN_ENUM_CONVERSION = YES; 202 | CLANG_WARN_INFINITE_RECURSION = YES; 203 | CLANG_WARN_INT_CONVERSION = YES; 204 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 205 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 206 | CLANG_WARN_UNREACHABLE_CODE = YES; 207 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 208 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 209 | COPY_PHASE_STRIP = NO; 210 | CURRENT_PROJECT_VERSION = 1; 211 | DEBUG_INFORMATION_FORMAT = dwarf; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | ENABLE_TESTABILITY = YES; 214 | GCC_C_LANGUAGE_STANDARD = gnu99; 215 | GCC_DYNAMIC_NO_PIC = NO; 216 | GCC_NO_COMMON_BLOCKS = YES; 217 | GCC_OPTIMIZATION_LEVEL = 0; 218 | GCC_PREPROCESSOR_DEFINITIONS = ( 219 | "DEBUG=1", 220 | "$(inherited)", 221 | ); 222 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 223 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 224 | GCC_WARN_UNDECLARED_SELECTOR = YES; 225 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 226 | GCC_WARN_UNUSED_FUNCTION = YES; 227 | GCC_WARN_UNUSED_VARIABLE = YES; 228 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 229 | MTL_ENABLE_DEBUG_INFO = YES; 230 | ONLY_ACTIVE_ARCH = YES; 231 | SDKROOT = iphoneos; 232 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 233 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 234 | TARGETED_DEVICE_FAMILY = "1,2"; 235 | VERSIONING_SYSTEM = "apple-generic"; 236 | VERSION_INFO_PREFIX = ""; 237 | }; 238 | name = Debug; 239 | }; 240 | 0499F57B1E8EF9B30003611B /* Release */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | ALWAYS_SEARCH_USER_PATHS = NO; 244 | CLANG_ANALYZER_NONNULL = YES; 245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 246 | CLANG_CXX_LIBRARY = "libc++"; 247 | CLANG_ENABLE_MODULES = YES; 248 | CLANG_ENABLE_OBJC_ARC = YES; 249 | CLANG_WARN_BOOL_CONVERSION = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INFINITE_RECURSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 259 | CLANG_WARN_UNREACHABLE_CODE = YES; 260 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 261 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 262 | COPY_PHASE_STRIP = NO; 263 | CURRENT_PROJECT_VERSION = 1; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | VERSIONING_SYSTEM = "apple-generic"; 282 | VERSION_INFO_PREFIX = ""; 283 | }; 284 | name = Release; 285 | }; 286 | 0499F57D1E8EF9B30003611B /* Debug */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | CLANG_ENABLE_MODULES = YES; 290 | CODE_SIGN_IDENTITY = ""; 291 | DEFINES_MODULE = YES; 292 | DEVELOPMENT_TEAM = TGW6PA8S8E; 293 | DYLIB_COMPATIBILITY_VERSION = 1; 294 | DYLIB_CURRENT_VERSION = 1; 295 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 296 | INFOPLIST_FILE = AudioArmada/Info.plist; 297 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 298 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 299 | PRODUCT_BUNDLE_IDENTIFIER = com.coreywalo.AudioArmada; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | SKIP_INSTALL = YES; 302 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 303 | SWIFT_VERSION = 3.0; 304 | }; 305 | name = Debug; 306 | }; 307 | 0499F57E1E8EF9B30003611B /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | CLANG_ENABLE_MODULES = YES; 311 | CODE_SIGN_IDENTITY = ""; 312 | DEFINES_MODULE = YES; 313 | DEVELOPMENT_TEAM = TGW6PA8S8E; 314 | DYLIB_COMPATIBILITY_VERSION = 1; 315 | DYLIB_CURRENT_VERSION = 1; 316 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 317 | INFOPLIST_FILE = AudioArmada/Info.plist; 318 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 319 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 320 | PRODUCT_BUNDLE_IDENTIFIER = com.coreywalo.AudioArmada; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | SKIP_INSTALL = YES; 323 | SWIFT_VERSION = 3.0; 324 | }; 325 | name = Release; 326 | }; 327 | /* End XCBuildConfiguration section */ 328 | 329 | /* Begin XCConfigurationList section */ 330 | 0499F56E1E8EF9B20003611B /* Build configuration list for PBXProject "AudioArmada" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | 0499F57A1E8EF9B30003611B /* Debug */, 334 | 0499F57B1E8EF9B30003611B /* Release */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Release; 338 | }; 339 | 0499F57C1E8EF9B30003611B /* Build configuration list for PBXNativeTarget "AudioArmada" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | 0499F57D1E8EF9B30003611B /* Debug */, 343 | 0499F57E1E8EF9B30003611B /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | /* End XCConfigurationList section */ 349 | }; 350 | rootObject = 0499F56B1E8EF9B20003611B /* Project object */; 351 | } 352 | -------------------------------------------------------------------------------- /AudioArmada.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AudioArmada.xcodeproj/xcshareddata/xcschemes/AudioArmada.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /AudioArmada.xcodeproj/xcuserdata/corey.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AudioArmada.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 0499F5731E8EF9B20003611B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /AudioArmada.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AudioArmada.xcworkspace/xcuserdata/corey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /AudioArmada/AudioArmada.h: -------------------------------------------------------------------------------- 1 | // 2 | // AudioArmada.h 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 3/31/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AudioArmada. 12 | FOUNDATION_EXPORT double AudioArmadaVersionNumber; 13 | 14 | //! Project version string for AudioArmada. 15 | FOUNDATION_EXPORT const unsigned char AudioArmadaVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AudioArmada/Classes/WaveformRolling.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformRolling.swift 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 4/5/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import Accelerate 12 | 13 | public class WaveformRolling : WaveformZoomable { 14 | 15 | public var history: Float = 1.0 { 16 | didSet { 17 | if history > 1.0 { 18 | history = 1.0 19 | } 20 | else if history < 0.01 { 21 | history = 0.01 22 | } 23 | 24 | self.setNeedsDisplay() 25 | } 26 | } 27 | 28 | private var buffer = [Float]() 29 | private var points = [CGPoint]() 30 | 31 | public func updateWithBuffer(_ buffer: [Float]) { 32 | // buffer 33 | let toRemove = Int((history * Float(self.buffer.count))) 34 | if self.buffer.count > 0 && toRemove < self.buffer.count { 35 | self.buffer.removeSubrange(0...toRemove) 36 | } 37 | 38 | self.buffer.append(contentsOf: buffer) 39 | 40 | DispatchQueue.main.async { 41 | self.setNeedsDisplay() 42 | } 43 | } 44 | 45 | override func makePoints() { 46 | if buffer.count == 0 { return } 47 | 48 | let viewWidth = bounds.width 49 | 50 | let sampleCount = Int(Float(buffer.count) * zoomFactor) 51 | // print(sampleCount) 52 | 53 | // grab every nth sample (samplesPerPixel) 54 | let samplesPerPixel = Int(floor(Float(sampleCount) / Float(viewWidth))) 55 | // print(samplesPerPixel) 56 | 57 | // the expected sample count 58 | let reducedSampleCount = sampleCount / samplesPerPixel 59 | // print(reducedSampleCount) 60 | 61 | // left channel 62 | var processingBuffer = [Float](repeating: 0.0, 63 | count: sampleCount) 64 | 65 | // get absolute values 66 | vDSP_vabs(buffer, 1, &processingBuffer, 1, vDSP_Length(sampleCount)) 67 | 68 | // This is supposed to do what I'm doing below - using a sliding window to find maximums, but it was producing strange results 69 | // vDSP_vswmax(processingBuffer, samplePrecision, &maxSamplesBuffer, 1, newSampleCount, vDSP_Length(samplePrecision)) 70 | 71 | // Instead, we use a for loop with a stride of length samplePrecision to specify a range of samples 72 | // This range is passed to our own maximumIn() method 73 | 74 | var maxSamplesBuffer = [Float](repeating: 0.0, 75 | count: reducedSampleCount) 76 | 77 | var offset = 0 78 | 79 | for i in stride(from: 0, to: sampleCount-samplesPerPixel, by: samplesPerPixel) { 80 | maxSamplesBuffer[offset] = maximumIn(processingBuffer, from: i, to: i+samplesPerPixel) 81 | offset = offset + 1 82 | } 83 | 84 | // Convert the maxSamplesBuffer values to CGPoints for drawing 85 | // We also normalize them for display here 86 | points = maxSamplesBuffer.enumerated().map({ (index, value) -> CGPoint in 87 | let normalized = normalizeForDisplay(value) 88 | let point = CGPoint(x: CGFloat(index), y: CGFloat(normalized)) 89 | return point 90 | }) 91 | 92 | // Interpolate points for smoother drawing 93 | for (index, point) in points.enumerated() { 94 | if index > 0 { 95 | let interpolatedPoint = CGPoint.lerp(start: points[index - 1], end: point, t: 0.5) 96 | points[index] = interpolatedPoint 97 | } 98 | } 99 | } 100 | 101 | 102 | override func drawDetailedWaveform(_ rect: CGRect) { 103 | let path = UIBezierPath() 104 | 105 | path.move(to: CGPoint(x: 0.0, y: rect.height/2)) 106 | 107 | for point in points { 108 | let drawFrom = CGPoint(x: point.x, y: path.currentPoint.y) 109 | 110 | path.move(to: drawFrom) 111 | 112 | // bottom half 113 | let drawPointBottom = CGPoint(x: point.x, y: path.currentPoint.y + (point.y)) 114 | path.addLine(to: drawPointBottom) 115 | 116 | path.close() 117 | 118 | // top half 119 | let drawPointTop = CGPoint(x: point.x, y: path.currentPoint.y - (point.y)) 120 | path.addLine(to: drawPointTop) 121 | 122 | path.close() 123 | } 124 | 125 | UIColor.orange.set() 126 | path.stroke() 127 | path.fill() 128 | } 129 | 130 | override func drawSoundcloudWaveform(_ rect: CGRect) { 131 | let path = UIBezierPath() 132 | 133 | path.move(to: CGPoint(x: 0.0, y: rect.height/2)) 134 | 135 | var index = 0 136 | 137 | while index < points.count { 138 | let point = points[index] 139 | 140 | let drawFrom = CGPoint(x: point.x, y: path.currentPoint.y) 141 | 142 | // bottom half 143 | path.move(to: drawFrom) 144 | 145 | let drawPointBottom = CGPoint(x: point.x, y: path.currentPoint.y + (point.y)) 146 | path.addLine(to: drawPointBottom) 147 | path.addLine(to: CGPoint(x: drawPointBottom.x + pixelWidth, y: drawPointBottom.y)) 148 | path.addLine(to: CGPoint(x: drawFrom.x + pixelWidth, y: drawFrom.y)) 149 | 150 | path.close() 151 | 152 | // top half 153 | path.move(to: drawFrom) 154 | 155 | let drawPointTop = CGPoint(x: point.x, y: path.currentPoint.y - (point.y)) 156 | path.addLine(to: drawPointTop) 157 | path.addLine(to: CGPoint(x: drawPointTop.x + pixelWidth, y: drawPointTop.y)) 158 | path.addLine(to: CGPoint(x: drawFrom.x + pixelWidth, y: drawFrom.y)) 159 | 160 | path.close() 161 | 162 | // increment index 163 | index = index + Int(pixelWidth) + Int(pixelSpacing) 164 | } 165 | 166 | UIColor.orange.set() 167 | path.stroke() 168 | path.fill() 169 | } 170 | 171 | override public func draw(_ rect: CGRect) { 172 | makePoints() 173 | 174 | // this clears the rect 175 | backgroundColor = .black 176 | 177 | switch style { 178 | case .detail: 179 | drawDetailedWaveform(rect) 180 | case .soundcloud: 181 | drawSoundcloudWaveform(rect) 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /AudioArmada/Classes/WaveformZoomable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformZoomable.swift 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 3/31/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AVFoundation 11 | import Accelerate 12 | 13 | public enum WaveformStyle { 14 | case detail, soundcloud 15 | } 16 | 17 | public class WaveformZoomable : UIView { 18 | 19 | public var zoomFactor: Float = 1.0 { 20 | didSet { 21 | if zoomFactor > 1.0 { 22 | zoomFactor = 1.0 23 | } 24 | else if zoomFactor < 0.01 { 25 | zoomFactor = 0.01 26 | } 27 | } 28 | } 29 | 30 | public var style: WaveformStyle = .detail { 31 | didSet { 32 | self.reload(zoomFactor: zoomFactor) 33 | } 34 | } 35 | 36 | struct readFile { 37 | static var floatValuesLeft = [Float]() 38 | static var floatValuesRight = [Float]() 39 | static var leftPoints = [CGPoint]() 40 | static var rightPoints = [CGPoint]() 41 | static var populated = false 42 | } 43 | 44 | let pixelWidth: CGFloat = 2.0 45 | let pixelSpacing: CGFloat = 2.0 46 | 47 | public convenience init(withFile: URL, style: WaveformStyle = .detail) { 48 | self.init() 49 | 50 | openFile(withFile) 51 | 52 | self.style = style 53 | } 54 | 55 | public func openFile(_ file: URL) { 56 | let audioFile = try! AVAudioFile(forReading: file) 57 | 58 | // specify the format we WANT for the buffer 59 | let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: audioFile.fileFormat.sampleRate, channels: audioFile.fileFormat.channelCount, interleaved: false) 60 | 61 | // initialize and fill the buffer 62 | let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: UInt32(audioFile.length)) 63 | try! audioFile.read(into: buffer) 64 | 65 | // copy buffer to readFile struct 66 | readFile.floatValuesLeft = Array(UnsafeBufferPointer(start: buffer.floatChannelData?[0], count:Int(buffer.frameLength))) 67 | 68 | readFile.populated = true 69 | 70 | reload(zoomFactor: zoomFactor) 71 | } 72 | 73 | public func reload(zoomFactor: Float = 1.0) { 74 | self.zoomFactor = zoomFactor 75 | setNeedsDisplay() 76 | } 77 | 78 | func makePoints() { 79 | if !readFile.populated { return } 80 | 81 | let viewWidth = bounds.width 82 | 83 | let sampleCount = Int(Float(readFile.floatValuesLeft.count) * zoomFactor) 84 | // print(sampleCount) 85 | 86 | // grab every nth sample (samplesPerPixel) 87 | let samplesPerPixel = Int(floor(Float(sampleCount) / Float(viewWidth))) 88 | // print(samplesPerPixel) 89 | 90 | // the expected sample count 91 | let reducedSampleCount = sampleCount / samplesPerPixel 92 | // print(reducedSampleCount) 93 | 94 | // left channel 95 | var processingBuffer = [Float](repeating: 0.0, 96 | count: sampleCount) 97 | 98 | // get absolute values 99 | vDSP_vabs(readFile.floatValuesLeft, 1, &processingBuffer, 1, vDSP_Length(sampleCount)) 100 | 101 | // This is supposed to do what I'm doing below - using a sliding window to find maximums, but it was producing strange results 102 | // vDSP_vswmax(processingBuffer, samplePrecision, &maxSamplesBuffer, 1, newSampleCount, vDSP_Length(samplePrecision)) 103 | 104 | // Instead, we use a for loop with a stride of length samplePrecision to specify a range of samples 105 | // This range is passed to our own maximumIn() method 106 | 107 | var maxSamplesBuffer = [Float](repeating: 0.0, 108 | count: reducedSampleCount) 109 | 110 | var offset = 0 111 | 112 | for i in stride(from: 0, to: sampleCount-samplesPerPixel, by: samplesPerPixel) { 113 | maxSamplesBuffer[offset] = maximumIn(processingBuffer, from: i, to: i+samplesPerPixel) 114 | offset = offset + 1 115 | } 116 | 117 | // Convert the maxSamplesBuffer values to CGPoints for drawing 118 | // We also normalize them for display here 119 | readFile.leftPoints = maxSamplesBuffer.enumerated().map({ (index, value) -> CGPoint in 120 | let normalized = normalizeForDisplay(value) 121 | let point = CGPoint(x: CGFloat(index), y: CGFloat(normalized)) 122 | return point 123 | }) 124 | 125 | // Interpolate points for smoother drawing 126 | for (index, point) in readFile.leftPoints.enumerated() { 127 | if index > 0 { 128 | let interpolatedPoint = CGPoint.lerp(start: readFile.leftPoints[index - 1], end: point, t: 0.5) 129 | readFile.leftPoints[index] = interpolatedPoint 130 | } 131 | } 132 | } 133 | 134 | func drawDetailedWaveform(_ rect: CGRect) { 135 | let path = UIBezierPath() 136 | 137 | path.move(to: CGPoint(x: 0.0, y: rect.height/2)) 138 | 139 | // left channel 140 | 141 | for point in readFile.leftPoints { 142 | let drawFrom = CGPoint(x: point.x, y: path.currentPoint.y) 143 | 144 | path.move(to: drawFrom) 145 | 146 | // bottom half 147 | let drawPointBottom = CGPoint(x: point.x, y: path.currentPoint.y + (point.y)) 148 | path.addLine(to: drawPointBottom) 149 | 150 | path.close() 151 | 152 | // top half 153 | let drawPointTop = CGPoint(x: point.x, y: path.currentPoint.y - (point.y)) 154 | path.addLine(to: drawPointTop) 155 | 156 | path.close() 157 | } 158 | 159 | UIColor.orange.set() 160 | path.stroke() 161 | path.fill() 162 | } 163 | 164 | func drawSoundcloudWaveform(_ rect: CGRect) { 165 | let path = UIBezierPath() 166 | 167 | path.move(to: CGPoint(x: 0.0, y: rect.height/2)) 168 | 169 | // left channel 170 | 171 | var index = 0 172 | 173 | while index < readFile.leftPoints.count { 174 | let point = readFile.leftPoints[index] 175 | 176 | let drawFrom = CGPoint(x: point.x, y: path.currentPoint.y) 177 | 178 | // bottom half 179 | path.move(to: drawFrom) 180 | 181 | let drawPointBottom = CGPoint(x: point.x, y: path.currentPoint.y + (point.y)) 182 | path.addLine(to: drawPointBottom) 183 | path.addLine(to: CGPoint(x: drawPointBottom.x + pixelWidth, y: drawPointBottom.y)) 184 | path.addLine(to: CGPoint(x: drawFrom.x + pixelWidth, y: drawFrom.y)) 185 | 186 | path.close() 187 | 188 | // top half 189 | path.move(to: drawFrom) 190 | 191 | let drawPointTop = CGPoint(x: point.x, y: path.currentPoint.y - (point.y)) 192 | path.addLine(to: drawPointTop) 193 | path.addLine(to: CGPoint(x: drawPointTop.x + pixelWidth, y: drawPointTop.y)) 194 | path.addLine(to: CGPoint(x: drawFrom.x + pixelWidth, y: drawFrom.y)) 195 | 196 | path.close() 197 | 198 | // increment index 199 | index = index + Int(pixelWidth) + Int(pixelSpacing) 200 | } 201 | 202 | UIColor.orange.set() 203 | path.stroke() 204 | path.fill() 205 | } 206 | 207 | override public func draw(_ rect: CGRect) { 208 | makePoints() 209 | 210 | // this clears the rect 211 | backgroundColor = .black 212 | 213 | switch style { 214 | case .detail: 215 | drawDetailedWaveform(rect) 216 | case .soundcloud: 217 | drawSoundcloudWaveform(rect) 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /AudioArmada/Extensions/CGPoint+Operators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPoint+Operators.swift 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 4/3/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension CGPoint { 12 | static public func + (left: CGPoint, right: CGPoint) -> CGPoint { 13 | return CGPoint(x: left.x + right.x, y: left.y + right.y) 14 | } 15 | 16 | static public func - (left: CGPoint, right: CGPoint) -> CGPoint { 17 | return CGPoint(x: left.x - right.x, y: left.y - right.y) 18 | } 19 | 20 | static public func * (point: CGPoint, scalar: CGFloat) -> CGPoint { 21 | return CGPoint(x: point.x * scalar, y: point.y * scalar) 22 | } 23 | 24 | static public func lerp(start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { 25 | return start + (end - start) * t 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AudioArmada/Extensions/UIView+Normalize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Normalize.swift 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 4/3/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension UIView { 12 | public func normalizeForDisplay(_ value: Float) -> Float { 13 | let maxHeight = Float(bounds.height) 14 | let minHeight = Float(maxHeight / 2.0) 15 | let normalized = value * minHeight 16 | return normalized 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AudioArmada/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AudioArmada/Utilities/AAMath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAMath.swift 3 | // AudioArmada 4 | // 5 | // Created by Corey Walo on 4/3/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // This implementation is nearly identical to vDSP_vswmax, buuuut we're doing it in swift so I'm certain there's a performance hit 12 | public func maximumIn(_ array: [Float], from: Int, to: Int) -> Float { 13 | var max: Float = -Float.infinity 14 | 15 | for index in from...to { 16 | if array[index] > max { 17 | max = array[index] 18 | } 19 | } 20 | 21 | return max 22 | } 23 | 24 | public func minimumIn(_ array: [Float], from: Int, to: Int) -> Float { 25 | var min: Float = Float.infinity 26 | 27 | for index in from...to { 28 | if array[index] < min { 29 | min = array[index] 30 | } 31 | } 32 | 33 | return min 34 | } 35 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0499F58C1E8EF9D40003611B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0499F58B1E8EF9D40003611B /* AppDelegate.swift */; }; 11 | 0499F58E1E8EF9D40003611B /* WaveformZoomableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0499F58D1E8EF9D40003611B /* WaveformZoomableViewController.swift */; }; 12 | 0499F5911E8EF9D40003611B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0499F58F1E8EF9D40003611B /* Main.storyboard */; }; 13 | 0499F5931E8EF9D40003611B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0499F5921E8EF9D40003611B /* Assets.xcassets */; }; 14 | 0499F5961E8EF9D40003611B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0499F5941E8EF9D40003611B /* LaunchScreen.storyboard */; }; 15 | 0499F5A51E8EFA3F0003611B /* Beat9.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 0499F5A41E8EFA3F0003611B /* Beat9.mp3 */; }; 16 | 0499F5BB1E8EFBAB0003611B /* AudioArmada.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0499F5B21E8EFB5A0003611B /* AudioArmada.framework */; }; 17 | 0499F5BC1E8EFBAB0003611B /* AudioArmada.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0499F5B21E8EFB5A0003611B /* AudioArmada.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 0499F5C41E8F02DF0003611B /* WaveformZoomableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0499F5C31E8F02DF0003611B /* WaveformZoomableView.swift */; }; 19 | 0499F5CD1E8F0C890003611B /* Divergence.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0499F5CC1E8F0C890003611B /* Divergence.wav */; }; 20 | 0499F5CF1E8F0DDC0003611B /* drumLoop.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0499F5CE1E8F0DDC0003611B /* drumLoop.wav */; }; 21 | 04FBAEDD1E93024E003D123F /* ExamplesListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBAEDC1E93024E003D123F /* ExamplesListViewController.swift */; }; 22 | 04FBAEE21E9305B6003D123F /* ExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBAEE11E9305B6003D123F /* ExampleViewController.swift */; }; 23 | 04FE9AD01E95FDAB00DEC4D4 /* WaveformRollingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FE9ACF1E95FDAB00DEC4D4 /* WaveformRollingViewController.swift */; }; 24 | 04FE9AD21E95FDBE00DEC4D4 /* WaveformRollingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FE9AD11E95FDBE00DEC4D4 /* WaveformRollingView.swift */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 0499F5B11E8EFB5A0003611B /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */; 31 | proxyType = 2; 32 | remoteGlobalIDString = 0499F5741E8EF9B20003611B; 33 | remoteInfo = AudioArmada; 34 | }; 35 | 0499F5B81E8EFBA30003611B /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 0499F5731E8EF9B20003611B; 40 | remoteInfo = AudioArmada; 41 | }; 42 | 0499F5BD1E8EFBAB0003611B /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 0499F5731E8EF9B20003611B; 47 | remoteInfo = AudioArmada; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 0499F5BF1E8EFBAB0003611B /* Embed Frameworks */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 10; 57 | files = ( 58 | 0499F5BC1E8EFBAB0003611B /* AudioArmada.framework in Embed Frameworks */, 59 | ); 60 | name = "Embed Frameworks"; 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXCopyFilesBuildPhase section */ 64 | 65 | /* Begin PBXFileReference section */ 66 | 0499F5881E8EF9D40003611B /* AudioArmadaExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AudioArmadaExamples.app; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 0499F58B1E8EF9D40003611B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Source/AppDelegate.swift; sourceTree = ""; }; 68 | 0499F58D1E8EF9D40003611B /* WaveformZoomableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WaveformZoomableViewController.swift; path = Source/WaveformZoomableViewController.swift; sourceTree = ""; }; 69 | 0499F5901E8EF9D40003611B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 70 | 0499F5921E8EF9D40003611B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | 0499F5951E8EF9D40003611B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 72 | 0499F5971E8EF9D40003611B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 0499F5A41E8EFA3F0003611B /* Beat9.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Beat9.mp3; path = "Audio Samples/Beat9.mp3"; sourceTree = ""; }; 74 | 0499F5A71E8EFA540003611B /* AudioArmada.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioArmada.framework; path = "../build/Debug-iphoneos/AudioArmada.framework"; sourceTree = ""; }; 75 | 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AudioArmada.xcodeproj; path = ../AudioArmada.xcodeproj; sourceTree = ""; }; 76 | 0499F5C31E8F02DF0003611B /* WaveformZoomableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WaveformZoomableView.swift; path = Source/WaveformZoomableView.swift; sourceTree = ""; }; 77 | 0499F5C51E8F071F0003611B /* Restraint.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Restraint.framework; path = Carthage/Build/iOS/Restraint.framework; sourceTree = ""; }; 78 | 0499F5CC1E8F0C890003611B /* Divergence.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = Divergence.wav; path = "Audio Samples/Divergence.wav"; sourceTree = ""; }; 79 | 0499F5CE1E8F0DDC0003611B /* drumLoop.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = drumLoop.wav; path = "Audio Samples/drumLoop.wav"; sourceTree = ""; }; 80 | 04FBAEDC1E93024E003D123F /* ExamplesListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExamplesListViewController.swift; path = Source/ExamplesListViewController.swift; sourceTree = ""; }; 81 | 04FBAEE11E9305B6003D123F /* ExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExampleViewController.swift; path = Source/ExampleViewController.swift; sourceTree = ""; }; 82 | 04FE9ACF1E95FDAB00DEC4D4 /* WaveformRollingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WaveformRollingViewController.swift; path = Source/WaveformRollingViewController.swift; sourceTree = ""; }; 83 | 04FE9AD11E95FDBE00DEC4D4 /* WaveformRollingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WaveformRollingView.swift; path = Source/WaveformRollingView.swift; sourceTree = ""; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | 0499F5851E8EF9D40003611B /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | 0499F5BB1E8EFBAB0003611B /* AudioArmada.framework in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 0499F57F1E8EF9D40003611B = { 99 | isa = PBXGroup; 100 | children = ( 101 | 0499F58A1E8EF9D40003611B /* Source */, 102 | 0499F5A31E8EFA320003611B /* Audio Samples */, 103 | 0499F5891E8EF9D40003611B /* Products */, 104 | 0499F5A61E8EFA540003611B /* Frameworks */, 105 | 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 0499F5891E8EF9D40003611B /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 0499F5881E8EF9D40003611B /* AudioArmadaExamples.app */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | 0499F58A1E8EF9D40003611B /* Source */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 0499F58B1E8EF9D40003611B /* AppDelegate.swift */, 121 | 04FBAEDF1E9302DD003D123F /* Examples */, 122 | 04FBAEE01E93036E003D123F /* Supporting Files */, 123 | ); 124 | name = Source; 125 | path = AudioArmadaExamples; 126 | sourceTree = ""; 127 | }; 128 | 0499F5A31E8EFA320003611B /* Audio Samples */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 0499F5CC1E8F0C890003611B /* Divergence.wav */, 132 | 0499F5A41E8EFA3F0003611B /* Beat9.mp3 */, 133 | 0499F5CE1E8F0DDC0003611B /* drumLoop.wav */, 134 | ); 135 | name = "Audio Samples"; 136 | path = AudioArmadaExamples; 137 | sourceTree = ""; 138 | }; 139 | 0499F5A61E8EFA540003611B /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 0499F5C51E8F071F0003611B /* Restraint.framework */, 143 | 0499F5A71E8EFA540003611B /* AudioArmada.framework */, 144 | ); 145 | name = Frameworks; 146 | sourceTree = ""; 147 | }; 148 | 0499F5AE1E8EFB5A0003611B /* Products */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 0499F5B21E8EFB5A0003611B /* AudioArmada.framework */, 152 | ); 153 | name = Products; 154 | sourceTree = ""; 155 | }; 156 | 04FBAEDE1E9302CB003D123F /* WaveformZoomableExample */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 0499F58D1E8EF9D40003611B /* WaveformZoomableViewController.swift */, 160 | 0499F5C31E8F02DF0003611B /* WaveformZoomableView.swift */, 161 | ); 162 | name = WaveformZoomableExample; 163 | sourceTree = ""; 164 | }; 165 | 04FBAEDF1E9302DD003D123F /* Examples */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 04FBAEDC1E93024E003D123F /* ExamplesListViewController.swift */, 169 | 04FBAEE11E9305B6003D123F /* ExampleViewController.swift */, 170 | 04FBAEDE1E9302CB003D123F /* WaveformZoomableExample */, 171 | 04FE9ACE1E95FD6A00DEC4D4 /* WaveformRollingExample */, 172 | ); 173 | name = Examples; 174 | sourceTree = ""; 175 | }; 176 | 04FBAEE01E93036E003D123F /* Supporting Files */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 0499F58F1E8EF9D40003611B /* Main.storyboard */, 180 | 0499F5921E8EF9D40003611B /* Assets.xcassets */, 181 | 0499F5941E8EF9D40003611B /* LaunchScreen.storyboard */, 182 | 0499F5971E8EF9D40003611B /* Info.plist */, 183 | ); 184 | name = "Supporting Files"; 185 | sourceTree = ""; 186 | }; 187 | 04FE9ACE1E95FD6A00DEC4D4 /* WaveformRollingExample */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 04FE9ACF1E95FDAB00DEC4D4 /* WaveformRollingViewController.swift */, 191 | 04FE9AD11E95FDBE00DEC4D4 /* WaveformRollingView.swift */, 192 | ); 193 | name = WaveformRollingExample; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXGroup section */ 197 | 198 | /* Begin PBXNativeTarget section */ 199 | 0499F5871E8EF9D40003611B /* AudioArmadaExamples */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 0499F59A1E8EF9D40003611B /* Build configuration list for PBXNativeTarget "AudioArmadaExamples" */; 202 | buildPhases = ( 203 | 0499F5841E8EF9D40003611B /* Sources */, 204 | 0499F5851E8EF9D40003611B /* Frameworks */, 205 | 0499F5861E8EF9D40003611B /* Resources */, 206 | 0499F5BF1E8EFBAB0003611B /* Embed Frameworks */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | 0499F5B91E8EFBA30003611B /* PBXTargetDependency */, 212 | 0499F5BE1E8EFBAB0003611B /* PBXTargetDependency */, 213 | ); 214 | name = AudioArmadaExamples; 215 | productName = AudioArmadaExamples; 216 | productReference = 0499F5881E8EF9D40003611B /* AudioArmadaExamples.app */; 217 | productType = "com.apple.product-type.application"; 218 | }; 219 | /* End PBXNativeTarget section */ 220 | 221 | /* Begin PBXProject section */ 222 | 0499F5801E8EF9D40003611B /* Project object */ = { 223 | isa = PBXProject; 224 | attributes = { 225 | LastSwiftUpdateCheck = 0820; 226 | LastUpgradeCheck = 0820; 227 | ORGANIZATIONNAME = "Corey Walo"; 228 | TargetAttributes = { 229 | 0499F5871E8EF9D40003611B = { 230 | CreatedOnToolsVersion = 8.2; 231 | DevelopmentTeam = TGW6PA8S8E; 232 | ProvisioningStyle = Automatic; 233 | }; 234 | }; 235 | }; 236 | buildConfigurationList = 0499F5831E8EF9D40003611B /* Build configuration list for PBXProject "AudioArmadaExamples" */; 237 | compatibilityVersion = "Xcode 3.2"; 238 | developmentRegion = English; 239 | hasScannedForEncodings = 0; 240 | knownRegions = ( 241 | en, 242 | Base, 243 | ); 244 | mainGroup = 0499F57F1E8EF9D40003611B; 245 | productRefGroup = 0499F5891E8EF9D40003611B /* Products */; 246 | projectDirPath = ""; 247 | projectReferences = ( 248 | { 249 | ProductGroup = 0499F5AE1E8EFB5A0003611B /* Products */; 250 | ProjectRef = 0499F5AD1E8EFB5A0003611B /* AudioArmada.xcodeproj */; 251 | }, 252 | ); 253 | projectRoot = ""; 254 | targets = ( 255 | 0499F5871E8EF9D40003611B /* AudioArmadaExamples */, 256 | ); 257 | }; 258 | /* End PBXProject section */ 259 | 260 | /* Begin PBXReferenceProxy section */ 261 | 0499F5B21E8EFB5A0003611B /* AudioArmada.framework */ = { 262 | isa = PBXReferenceProxy; 263 | fileType = wrapper.framework; 264 | path = AudioArmada.framework; 265 | remoteRef = 0499F5B11E8EFB5A0003611B /* PBXContainerItemProxy */; 266 | sourceTree = BUILT_PRODUCTS_DIR; 267 | }; 268 | /* End PBXReferenceProxy section */ 269 | 270 | /* Begin PBXResourcesBuildPhase section */ 271 | 0499F5861E8EF9D40003611B /* Resources */ = { 272 | isa = PBXResourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | 0499F5A51E8EFA3F0003611B /* Beat9.mp3 in Resources */, 276 | 0499F5961E8EF9D40003611B /* LaunchScreen.storyboard in Resources */, 277 | 0499F5CF1E8F0DDC0003611B /* drumLoop.wav in Resources */, 278 | 0499F5931E8EF9D40003611B /* Assets.xcassets in Resources */, 279 | 0499F5CD1E8F0C890003611B /* Divergence.wav in Resources */, 280 | 0499F5911E8EF9D40003611B /* Main.storyboard in Resources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXResourcesBuildPhase section */ 285 | 286 | /* Begin PBXSourcesBuildPhase section */ 287 | 0499F5841E8EF9D40003611B /* Sources */ = { 288 | isa = PBXSourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | 04FBAEE21E9305B6003D123F /* ExampleViewController.swift in Sources */, 292 | 0499F58E1E8EF9D40003611B /* WaveformZoomableViewController.swift in Sources */, 293 | 04FE9AD21E95FDBE00DEC4D4 /* WaveformRollingView.swift in Sources */, 294 | 0499F58C1E8EF9D40003611B /* AppDelegate.swift in Sources */, 295 | 04FE9AD01E95FDAB00DEC4D4 /* WaveformRollingViewController.swift in Sources */, 296 | 04FBAEDD1E93024E003D123F /* ExamplesListViewController.swift in Sources */, 297 | 0499F5C41E8F02DF0003611B /* WaveformZoomableView.swift in Sources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXSourcesBuildPhase section */ 302 | 303 | /* Begin PBXTargetDependency section */ 304 | 0499F5B91E8EFBA30003611B /* PBXTargetDependency */ = { 305 | isa = PBXTargetDependency; 306 | name = AudioArmada; 307 | targetProxy = 0499F5B81E8EFBA30003611B /* PBXContainerItemProxy */; 308 | }; 309 | 0499F5BE1E8EFBAB0003611B /* PBXTargetDependency */ = { 310 | isa = PBXTargetDependency; 311 | name = AudioArmada; 312 | targetProxy = 0499F5BD1E8EFBAB0003611B /* PBXContainerItemProxy */; 313 | }; 314 | /* End PBXTargetDependency section */ 315 | 316 | /* Begin PBXVariantGroup section */ 317 | 0499F58F1E8EF9D40003611B /* Main.storyboard */ = { 318 | isa = PBXVariantGroup; 319 | children = ( 320 | 0499F5901E8EF9D40003611B /* Base */, 321 | ); 322 | name = Main.storyboard; 323 | sourceTree = ""; 324 | }; 325 | 0499F5941E8EF9D40003611B /* LaunchScreen.storyboard */ = { 326 | isa = PBXVariantGroup; 327 | children = ( 328 | 0499F5951E8EF9D40003611B /* Base */, 329 | ); 330 | name = LaunchScreen.storyboard; 331 | sourceTree = ""; 332 | }; 333 | /* End PBXVariantGroup section */ 334 | 335 | /* Begin XCBuildConfiguration section */ 336 | 0499F5981E8EF9D40003611B /* Debug */ = { 337 | isa = XCBuildConfiguration; 338 | buildSettings = { 339 | ALWAYS_SEARCH_USER_PATHS = NO; 340 | CLANG_ANALYZER_NONNULL = YES; 341 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 342 | CLANG_CXX_LIBRARY = "libc++"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_WARN_BOOL_CONVERSION = YES; 346 | CLANG_WARN_CONSTANT_CONVERSION = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 349 | CLANG_WARN_EMPTY_BODY = YES; 350 | CLANG_WARN_ENUM_CONVERSION = YES; 351 | CLANG_WARN_INFINITE_RECURSION = YES; 352 | CLANG_WARN_INT_CONVERSION = YES; 353 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 354 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 355 | CLANG_WARN_UNREACHABLE_CODE = YES; 356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 358 | COPY_PHASE_STRIP = NO; 359 | DEBUG_INFORMATION_FORMAT = dwarf; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | ENABLE_TESTABILITY = YES; 362 | GCC_C_LANGUAGE_STANDARD = gnu99; 363 | GCC_DYNAMIC_NO_PIC = NO; 364 | GCC_NO_COMMON_BLOCKS = YES; 365 | GCC_OPTIMIZATION_LEVEL = 0; 366 | GCC_PREPROCESSOR_DEFINITIONS = ( 367 | "DEBUG=1", 368 | "$(inherited)", 369 | ); 370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 372 | GCC_WARN_UNDECLARED_SELECTOR = YES; 373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 374 | GCC_WARN_UNUSED_FUNCTION = YES; 375 | GCC_WARN_UNUSED_VARIABLE = YES; 376 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 377 | MTL_ENABLE_DEBUG_INFO = YES; 378 | ONLY_ACTIVE_ARCH = YES; 379 | SDKROOT = iphoneos; 380 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 381 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 382 | }; 383 | name = Debug; 384 | }; 385 | 0499F5991E8EF9D40003611B /* Release */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | ALWAYS_SEARCH_USER_PATHS = NO; 389 | CLANG_ANALYZER_NONNULL = YES; 390 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 391 | CLANG_CXX_LIBRARY = "libc++"; 392 | CLANG_ENABLE_MODULES = YES; 393 | CLANG_ENABLE_OBJC_ARC = YES; 394 | CLANG_WARN_BOOL_CONVERSION = YES; 395 | CLANG_WARN_CONSTANT_CONVERSION = YES; 396 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 397 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 398 | CLANG_WARN_EMPTY_BODY = YES; 399 | CLANG_WARN_ENUM_CONVERSION = YES; 400 | CLANG_WARN_INFINITE_RECURSION = YES; 401 | CLANG_WARN_INT_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 404 | CLANG_WARN_UNREACHABLE_CODE = YES; 405 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 406 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 407 | COPY_PHASE_STRIP = NO; 408 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 409 | ENABLE_NS_ASSERTIONS = NO; 410 | ENABLE_STRICT_OBJC_MSGSEND = YES; 411 | GCC_C_LANGUAGE_STANDARD = gnu99; 412 | GCC_NO_COMMON_BLOCKS = YES; 413 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 414 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 415 | GCC_WARN_UNDECLARED_SELECTOR = YES; 416 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 417 | GCC_WARN_UNUSED_FUNCTION = YES; 418 | GCC_WARN_UNUSED_VARIABLE = YES; 419 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 420 | MTL_ENABLE_DEBUG_INFO = NO; 421 | SDKROOT = iphoneos; 422 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 423 | VALIDATE_PRODUCT = YES; 424 | }; 425 | name = Release; 426 | }; 427 | 0499F59B1E8EF9D40003611B /* Debug */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 431 | DEVELOPMENT_TEAM = TGW6PA8S8E; 432 | FRAMEWORK_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "$(PROJECT_DIR)/Carthage/Build/iOS", 435 | ); 436 | INFOPLIST_FILE = AudioArmadaExamples/Info.plist; 437 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 438 | PRODUCT_BUNDLE_IDENTIFIER = com.coreywalo.AudioArmadaExamples; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | SWIFT_VERSION = 3.0; 441 | }; 442 | name = Debug; 443 | }; 444 | 0499F59C1E8EF9D40003611B /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 448 | DEVELOPMENT_TEAM = TGW6PA8S8E; 449 | FRAMEWORK_SEARCH_PATHS = ( 450 | "$(inherited)", 451 | "$(PROJECT_DIR)/Carthage/Build/iOS", 452 | ); 453 | INFOPLIST_FILE = AudioArmadaExamples/Info.plist; 454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 455 | PRODUCT_BUNDLE_IDENTIFIER = com.coreywalo.AudioArmadaExamples; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | SWIFT_VERSION = 3.0; 458 | }; 459 | name = Release; 460 | }; 461 | /* End XCBuildConfiguration section */ 462 | 463 | /* Begin XCConfigurationList section */ 464 | 0499F5831E8EF9D40003611B /* Build configuration list for PBXProject "AudioArmadaExamples" */ = { 465 | isa = XCConfigurationList; 466 | buildConfigurations = ( 467 | 0499F5981E8EF9D40003611B /* Debug */, 468 | 0499F5991E8EF9D40003611B /* Release */, 469 | ); 470 | defaultConfigurationIsVisible = 0; 471 | defaultConfigurationName = Release; 472 | }; 473 | 0499F59A1E8EF9D40003611B /* Build configuration list for PBXNativeTarget "AudioArmadaExamples" */ = { 474 | isa = XCConfigurationList; 475 | buildConfigurations = ( 476 | 0499F59B1E8EF9D40003611B /* Debug */, 477 | 0499F59C1E8EF9D40003611B /* Release */, 478 | ); 479 | defaultConfigurationIsVisible = 0; 480 | defaultConfigurationName = Release; 481 | }; 482 | /* End XCConfigurationList section */ 483 | }; 484 | rootObject = 0499F5801E8EF9D40003611B /* Project object */; 485 | } 486 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples.xcodeproj/xcuserdata/corey.xcuserdatad/xcschemes/AudioArmadaExamples.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples.xcodeproj/xcuserdata/corey.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AudioArmadaExamples.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 0499F5871E8EF9D40003611B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Assets.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 | } -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Audio Samples/Beat9.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwalo/AudioArmada/90f214d3d9483e817cdb1396e08f8f626a7be821/AudioArmadaExamples/AudioArmadaExamples/Audio Samples/Beat9.mp3 -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Audio Samples/Divergence.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwalo/AudioArmada/90f214d3d9483e817cdb1396e08f8f626a7be821/AudioArmadaExamples/AudioArmadaExamples/Audio Samples/Divergence.wav -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Audio Samples/drumLoop.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwalo/AudioArmada/90f214d3d9483e817cdb1396e08f8f626a7be821/AudioArmadaExamples/AudioArmadaExamples/Audio Samples/drumLoop.wav -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 3/31/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | 18 | window = UIWindow() 19 | window?.rootViewController = UINavigationController(rootViewController: ExamplesListViewController()) 20 | window?.makeKeyAndVisible() 21 | 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 4/3/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | protocol ExampleViewController : class { 13 | static var displayName: String { get } 14 | } 15 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/ExamplesListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExamplesListViewController.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 4/3/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ExamplesListViewController: UITableViewController { 12 | 13 | let examples: [UIViewController.Type] = [WaveformZoomableViewController.self, 14 | WaveformRollingViewController.self] 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | title = "Examples" 20 | 21 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "exampleCell") 22 | } 23 | 24 | // MARK: - Table view data source 25 | 26 | override func numberOfSections(in tableView: UITableView) -> Int { 27 | return 1 28 | } 29 | 30 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 31 | return examples.count 32 | } 33 | 34 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 35 | let cell = tableView.dequeueReusableCell(withIdentifier: "exampleCell", for: indexPath) 36 | 37 | let controller = examples[indexPath.row] as! ExampleViewController.Type 38 | cell.textLabel?.text = controller.displayName 39 | 40 | return cell 41 | } 42 | 43 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 44 | let controllerClass = examples[indexPath.row] 45 | 46 | navigationController?.pushViewController(controllerClass.init(), animated: true) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/WaveformRollingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformRollingView.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 4/5/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AudioArmada 11 | 12 | class WaveformRollingView : UIView { 13 | let styleToggle = UISegmentedControl() 14 | let waveform = WaveformRolling() 15 | 16 | let sliderTitle = UILabel() 17 | let slider = UISlider() 18 | let sliderLabel = UILabel() 19 | 20 | let historySliderTitle = UILabel() 21 | let historySlider = UISlider() 22 | let historySliderLabel = UILabel() 23 | 24 | let playButton = UIButton() 25 | let stopButton = UIButton() 26 | 27 | override init(frame: CGRect) { 28 | super.init(frame: frame) 29 | 30 | layoutView() 31 | } 32 | 33 | required init?(coder aDecoder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | func layoutView() { 38 | backgroundColor = .white 39 | 40 | sliderTitle.text = "Zoom" 41 | historySliderTitle.text = "History" 42 | 43 | addSubview(styleToggle) 44 | addSubview(waveform) 45 | addSubview(sliderTitle) 46 | addSubview(slider) 47 | addSubview(sliderLabel) 48 | addSubview(historySliderTitle) 49 | addSubview(historySlider) 50 | addSubview(historySliderLabel) 51 | addSubview(playButton) 52 | addSubview(stopButton) 53 | 54 | styleToggle.translatesAutoresizingMaskIntoConstraints = false 55 | waveform.translatesAutoresizingMaskIntoConstraints = false 56 | sliderTitle.translatesAutoresizingMaskIntoConstraints = false 57 | slider.translatesAutoresizingMaskIntoConstraints = false 58 | sliderLabel.translatesAutoresizingMaskIntoConstraints = false 59 | historySliderTitle.translatesAutoresizingMaskIntoConstraints = false 60 | historySlider.translatesAutoresizingMaskIntoConstraints = false 61 | historySliderLabel.translatesAutoresizingMaskIntoConstraints = false 62 | playButton.translatesAutoresizingMaskIntoConstraints = false 63 | stopButton.translatesAutoresizingMaskIntoConstraints = false 64 | 65 | styleToggle.bottomAnchor.constraint(equalTo: waveform.topAnchor, constant: -20.0).isActive = true 66 | styleToggle.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 67 | 68 | waveform.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true 69 | waveform.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true 70 | waveform.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 71 | waveform.heightAnchor.constraint(equalToConstant: 200.0).isActive = true 72 | 73 | sliderTitle.trailingAnchor.constraint(equalTo: slider.leadingAnchor, constant: -10.0).isActive = true 74 | sliderTitle.centerYAnchor.constraint(equalTo: slider.centerYAnchor).isActive = true 75 | 76 | slider.widthAnchor.constraint(equalToConstant: 100.0).isActive = true 77 | slider.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true 78 | slider.topAnchor.constraint(equalTo: waveform.bottomAnchor, constant: 20.0).isActive = true 79 | 80 | sliderLabel.leadingAnchor.constraint(equalTo: slider.trailingAnchor, constant: 10.0).isActive = true 81 | sliderLabel.centerYAnchor.constraint(equalTo: slider.centerYAnchor).isActive = true 82 | 83 | historySliderTitle.trailingAnchor.constraint(equalTo: historySlider.leadingAnchor, constant: -10.0).isActive = true 84 | historySliderTitle.centerYAnchor.constraint(equalTo: historySlider.centerYAnchor).isActive = true 85 | 86 | historySlider.widthAnchor.constraint(equalToConstant: 100.0).isActive = true 87 | historySlider.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true 88 | historySlider.topAnchor.constraint(equalTo: slider.bottomAnchor, constant: 20.0).isActive = true 89 | 90 | historySliderLabel.leadingAnchor.constraint(equalTo: historySlider.trailingAnchor, constant: 10.0).isActive = true 91 | historySliderLabel.centerYAnchor.constraint(equalTo: historySlider.centerYAnchor).isActive = true 92 | 93 | playButton.topAnchor.constraint(equalTo: historySlider.bottomAnchor, constant: 15.0).isActive = true 94 | playButton.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true 95 | 96 | stopButton.topAnchor.constraint(equalTo: playButton.bottomAnchor, constant: 15.0).isActive = true 97 | stopButton.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/WaveformRollingViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformRollingViewController.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 4/5/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import AVFoundation 12 | import AudioArmada 13 | 14 | class WaveformRollingViewController : UIViewController, ExampleViewController { 15 | static var displayName: String = "WaveformRolling" 16 | 17 | var engine: AVAudioEngine! 18 | var player: AVAudioPlayerNode! 19 | var file = AVAudioFile() 20 | var buffer: AVAudioPCMBuffer! 21 | 22 | var styleToggle: UISegmentedControl! 23 | var waveform: WaveformRolling! 24 | var slider: UISlider! 25 | var sliderLabel: UILabel! 26 | var historySlider: UISlider! 27 | var historySliderLabel: UILabel! 28 | var playButton: UIButton! 29 | var stopButton: UIButton! 30 | 31 | override func viewDidLoad() { 32 | super.viewDidLoad() 33 | 34 | title = WaveformRollingViewController.displayName 35 | 36 | styleToggle.addTarget(self, action: #selector(self.didToggleStyle(_:)), for: .valueChanged) 37 | slider.addTarget(self, action: #selector(self.didSlide(_:)), for: .valueChanged) 38 | historySlider.addTarget(self, action: #selector(self.didSlideHistory(_:)), for: .valueChanged) 39 | 40 | playButton.addTarget(self, action: #selector(self.didPressPlay), for: .touchUpInside) 41 | stopButton.addTarget(self, action: #selector(self.didPressStop), for: .touchUpInside) 42 | 43 | engine = AVAudioEngine() 44 | player = AVAudioPlayerNode() 45 | 46 | guard let url = Bundle.main.url(forResource: "drumLoop", withExtension: "wav") else { return } 47 | 48 | file = try! AVAudioFile(forReading: url) 49 | 50 | // need to specify the format, because engine channel count is stereo by default 51 | let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.fileFormat.sampleRate, channels: file.fileFormat.channelCount, interleaved: false) 52 | 53 | buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(file.length)) 54 | try! file.read(into: buffer) 55 | 56 | engine.attach(player) 57 | engine.connect(player, to: engine.mainMixerNode, format: format) 58 | 59 | engine.mainMixerNode.installTap(onBus: 0, bufferSize: 1024, format: format) { (buffer, time) in 60 | let length = buffer.frameLength 61 | let floatArray = Array(UnsafeBufferPointer(start: buffer.floatChannelData?[0], count: Int(length))) 62 | self.waveform.updateWithBuffer(floatArray) 63 | } 64 | 65 | engine.prepare() 66 | try! engine.start() 67 | } 68 | 69 | func didSlide(_ sender: UISlider) { 70 | // invert the values that represent the zoomFactor since we want to zoom IN as we slide left to right 71 | let zoomFactor = sender.maximumValue - sender.value + sender.minimumValue; 72 | sliderLabel.text = "\(zoomFactor * 100.0) %" 73 | waveform.reload(zoomFactor: zoomFactor) 74 | } 75 | 76 | func didSlideHistory(_ sender: UISlider) { 77 | // invert the values that represent the zoomFactor since we want to zoom IN as we slide left to right 78 | let history = sender.maximumValue - sender.value + sender.minimumValue; 79 | historySliderLabel.text = "\(history * 100.0) %" 80 | waveform.history = history 81 | } 82 | 83 | func didToggleStyle(_ sender: UISegmentedControl) { 84 | switch sender.selectedSegmentIndex { 85 | case 0: 86 | waveform.style = .detail 87 | case 1: 88 | waveform.style = .soundcloud 89 | default: 90 | break 91 | } 92 | } 93 | 94 | func didPressPlay() { 95 | if engine.isRunning { 96 | player.scheduleBuffer(buffer, at: nil, options: .loops, completionHandler: nil) 97 | player.play() 98 | } 99 | } 100 | 101 | func didPressStop() { 102 | if engine.isRunning { 103 | player.stop() 104 | } 105 | } 106 | 107 | override func loadView() { 108 | let waveformView = WaveformRollingView() 109 | styleToggle = waveformView.styleToggle 110 | waveform = waveformView.waveform 111 | slider = waveformView.slider 112 | sliderLabel = waveformView.sliderLabel 113 | historySlider = waveformView.historySlider 114 | historySliderLabel = waveformView.historySliderLabel 115 | 116 | styleToggle.insertSegment(withTitle: "Detailed", at: 0, animated: false) 117 | styleToggle.insertSegment(withTitle: "Soundcloud", at: 1, animated: false) 118 | styleToggle.selectedSegmentIndex = 0 119 | 120 | // set min-max to show 1%-100% of the waveform 121 | slider.minimumValue = 0.01 122 | slider.maximumValue = 1.0 123 | slider.setValue(slider.minimumValue, animated: false) 124 | 125 | sliderLabel.text = "100.0 %" 126 | 127 | // set min-max to show 1%-100% of the waveform 128 | historySlider.minimumValue = 0.01 129 | historySlider.maximumValue = 1.0 130 | historySlider.setValue(slider.minimumValue, animated: false) 131 | 132 | historySliderLabel.text = "100.0 %" 133 | 134 | playButton = waveformView.playButton 135 | stopButton = waveformView.stopButton 136 | 137 | playButton.setTitle("Play", for: .normal) 138 | playButton.setTitleColor(.black, for: .normal) 139 | stopButton.setTitle("Stop", for: .normal) 140 | stopButton.setTitleColor(.black, for: .normal) 141 | 142 | view = waveformView 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/WaveformZoomableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformZoomableView.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 3/31/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AudioArmada 11 | 12 | class WaveformZoomableView: UIView { 13 | 14 | let styleToggle = UISegmentedControl() 15 | let waveform = WaveformZoomable() 16 | let slider = UISlider() 17 | let sliderLabel = UILabel() 18 | 19 | override init(frame: CGRect) { 20 | super.init(frame: frame) 21 | 22 | layoutView() 23 | } 24 | 25 | required init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | 29 | func layoutView() { 30 | backgroundColor = .white 31 | 32 | addSubview(styleToggle) 33 | addSubview(waveform) 34 | addSubview(slider) 35 | addSubview(sliderLabel) 36 | 37 | styleToggle.translatesAutoresizingMaskIntoConstraints = false 38 | waveform.translatesAutoresizingMaskIntoConstraints = false 39 | slider.translatesAutoresizingMaskIntoConstraints = false 40 | sliderLabel.translatesAutoresizingMaskIntoConstraints = false 41 | 42 | styleToggle.bottomAnchor.constraint(equalTo: waveform.topAnchor, constant: -20.0).isActive = true 43 | styleToggle.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 44 | 45 | waveform.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true 46 | waveform.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true 47 | waveform.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 48 | waveform.heightAnchor.constraint(equalToConstant: 200.0).isActive = true 49 | 50 | slider.widthAnchor.constraint(equalToConstant: 100.0).isActive = true 51 | slider.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true 52 | slider.topAnchor.constraint(equalTo: waveform.bottomAnchor, constant: 20.0).isActive = true 53 | 54 | sliderLabel.leadingAnchor.constraint(equalTo: slider.trailingAnchor, constant: 10.0).isActive = true 55 | sliderLabel.centerYAnchor.constraint(equalTo: slider.centerYAnchor).isActive = true 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AudioArmadaExamples/AudioArmadaExamples/Source/WaveformZoomableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveformZoomableViewController.swift 3 | // AudioArmadaExamples 4 | // 5 | // Created by Corey Walo on 3/31/17. 6 | // Copyright © 2017 Corey Walo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AudioArmada 11 | 12 | class WaveformZoomableViewController: UIViewController, ExampleViewController { 13 | 14 | static var displayName: String = "WaveformZoomable" 15 | 16 | var styleToggle: UISegmentedControl! 17 | var waveform: WaveformZoomable! 18 | var slider: UISlider! 19 | var sliderLabel: UILabel! 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | title = WaveformZoomableViewController.displayName 25 | 26 | // open the audio file and set the display style 27 | guard let file = Bundle.main.url(forResource: "drumLoop", withExtension: "wav") else { return } 28 | waveform.openFile(file) 29 | 30 | styleToggle.addTarget(self, action: #selector(self.didToggleStyle(_:)), for: .valueChanged) 31 | slider.addTarget(self, action: #selector(self.didSlide(_:)), for: .valueChanged) 32 | } 33 | 34 | func didSlide(_ sender: UISlider) { 35 | // invert the values that represent the zoomFactor since we want to zoom IN as we slide left to right 36 | let zoomFactor = sender.maximumValue - sender.value + sender.minimumValue; 37 | sliderLabel.text = "\(zoomFactor * 100.0) %" 38 | waveform.reload(zoomFactor: zoomFactor) 39 | } 40 | 41 | func didToggleStyle(_ sender: UISegmentedControl) { 42 | switch sender.selectedSegmentIndex { 43 | case 0: 44 | waveform.style = .detail 45 | case 1: 46 | waveform.style = .soundcloud 47 | default: 48 | break 49 | } 50 | } 51 | 52 | override func loadView() { 53 | let waveformView = WaveformZoomableView() 54 | styleToggle = waveformView.styleToggle 55 | waveform = waveformView.waveform 56 | slider = waveformView.slider 57 | sliderLabel = waveformView.sliderLabel 58 | 59 | styleToggle.insertSegment(withTitle: "Detailed", at: 0, animated: false) 60 | styleToggle.insertSegment(withTitle: "Soundcloud", at: 1, animated: false) 61 | styleToggle.selectedSegmentIndex = 0 62 | 63 | // set min-max to show 1%-100% of the waveform 64 | slider.minimumValue = 0.01 65 | slider.maximumValue = 1.0 66 | slider.setValue(slider.minimumValue, animated: false) 67 | 68 | sliderLabel.text = "100.0 %" 69 | 70 | view = waveformView 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /AudioArmadaExamples/Cartfile: -------------------------------------------------------------------------------- 1 | github "puffinsupply/Restraint" "master" -------------------------------------------------------------------------------- /AudioArmadaExamples/Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "puffinsupply/Restraint" "661d7143e3efe6c4185424e88b91a7bb8f4e6694" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Corey Walo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /images/waveform_rolling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwalo/AudioArmada/90f214d3d9483e817cdb1396e08f8f626a7be821/images/waveform_rolling.gif -------------------------------------------------------------------------------- /images/waveform_zoomable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cwalo/AudioArmada/90f214d3d9483e817cdb1396e08f8f626a7be821/images/waveform_zoomable.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Audio Armada 2 | #### The beginnings of an iOS audio toolkit 3 | 4 | I'm starting this as a test bed for mobile audio and framework design. Hopefully it gets to a point that developers can use it in their own applications. 5 | 6 | 7 | ## Classes 8 | **WaveformZoomable** - draw zoomable waveforms from audio files with multiple styles (detailed or Soundcloud-like) 9 | 10 | ![WaveformZoomable](images/waveform_zoomable.png) 11 | 12 | **WaveformRolling** - like WaveformZoomable, but designed for rolling (live) waveforms with variable history 13 | 14 | ![WaveformZoomable](images/waveform_rolling.gif) 15 | 16 | **More TBD...** 17 | 18 | ## Examples 19 | The examples are contained in the `AudioArmadaExamples` project. Just open the workspace and run the contained project. 20 | 21 | 22 | ## Installation 23 | 24 | ### Carthage 25 | 26 | Add the following to your project's `Cartfile`: 27 | 28 | `github "cwalo/AudioArmada" "master"` 29 | --------------------------------------------------------------------------------