├── .gitignore ├── Demo ├── SCSiriWaveformView.xcodeproj │ └── project.pbxproj └── SCSiriWaveformView │ ├── Base.lproj │ └── Main_iPad.storyboard │ ├── Main_iPhone.storyboard │ ├── SCAppDelegate.h │ ├── SCAppDelegate.m │ ├── SCSiriWaveformView-Info.plist │ ├── SCViewController.h │ ├── SCViewController.m │ ├── main.m │ └── sample.m4a ├── LICENSE ├── README.md ├── SCSiriWaveformView.podspec └── SCSiriWaveformView ├── SCSiriWaveformView.h └── SCSiriWaveformView.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 186F7B7818FAEC1100CCC606 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 186F7B7718FAEC1100CCC606 /* Foundation.framework */; }; 11 | 186F7B7A18FAEC1100CCC606 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 186F7B7918FAEC1100CCC606 /* CoreGraphics.framework */; }; 12 | 186F7B7C18FAEC1100CCC606 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 186F7B7B18FAEC1100CCC606 /* UIKit.framework */; }; 13 | 186F7B8418FAEC1100CCC606 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 186F7B8318FAEC1100CCC606 /* main.m */; }; 14 | 186F7B8818FAEC1100CCC606 /* SCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 186F7B8718FAEC1100CCC606 /* SCAppDelegate.m */; }; 15 | 186F7B8B18FAEC1100CCC606 /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 186F7B8918FAEC1100CCC606 /* Main_iPad.storyboard */; }; 16 | 186F7B8E18FAEC1100CCC606 /* SCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 186F7B8D18FAEC1100CCC606 /* SCViewController.m */; }; 17 | 186F7BB018FAEC6A00CCC606 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 186F7BAF18FAEC6A00CCC606 /* AVFoundation.framework */; }; 18 | 186F7BF618FAF5B500CCC606 /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 186F7BF518FAF5B500CCC606 /* Main_iPhone.storyboard */; }; 19 | 186F7BFA18FAF77500CCC606 /* SCSiriWaveformView.m in Sources */ = {isa = PBXBuildFile; fileRef = 186F7BF918FAF77500CCC606 /* SCSiriWaveformView.m */; }; 20 | 18EF32411B2479B600204641 /* sample.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 18EF32401B2479B600204641 /* sample.m4a */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 186F7B7418FAEC1100CCC606 /* SCSiriWaveformView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SCSiriWaveformView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 186F7B7718FAEC1100CCC606 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 26 | 186F7B7918FAEC1100CCC606 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 27 | 186F7B7B18FAEC1100CCC606 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28 | 186F7B7F18FAEC1100CCC606 /* SCSiriWaveformView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SCSiriWaveformView-Info.plist"; sourceTree = ""; }; 29 | 186F7B8318FAEC1100CCC606 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | 186F7B8618FAEC1100CCC606 /* SCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCAppDelegate.h; sourceTree = ""; }; 31 | 186F7B8718FAEC1100CCC606 /* SCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCAppDelegate.m; sourceTree = ""; }; 32 | 186F7B8A18FAEC1100CCC606 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; 33 | 186F7B8C18FAEC1100CCC606 /* SCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCViewController.h; sourceTree = ""; }; 34 | 186F7B8D18FAEC1100CCC606 /* SCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCViewController.m; sourceTree = ""; }; 35 | 186F7BAF18FAEC6A00CCC606 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 36 | 186F7BF518FAF5B500CCC606 /* Main_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main_iPhone.storyboard; sourceTree = ""; }; 37 | 186F7BF818FAF77500CCC606 /* SCSiriWaveformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCSiriWaveformView.h; sourceTree = ""; }; 38 | 186F7BF918FAF77500CCC606 /* SCSiriWaveformView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCSiriWaveformView.m; sourceTree = ""; }; 39 | 18EF32401B2479B600204641 /* sample.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample.m4a; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 186F7B7118FAEC1100CCC606 /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | 186F7BB018FAEC6A00CCC606 /* AVFoundation.framework in Frameworks */, 48 | 186F7B7A18FAEC1100CCC606 /* CoreGraphics.framework in Frameworks */, 49 | 186F7B7C18FAEC1100CCC606 /* UIKit.framework in Frameworks */, 50 | 186F7B7818FAEC1100CCC606 /* Foundation.framework in Frameworks */, 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXFrameworksBuildPhase section */ 55 | 56 | /* Begin PBXGroup section */ 57 | 186F7B6B18FAEC1100CCC606 = { 58 | isa = PBXGroup; 59 | children = ( 60 | 186F7BF718FAF77500CCC606 /* SCSiriWaveformView */, 61 | 186F7B7D18FAEC1100CCC606 /* Demo */, 62 | 186F7B7618FAEC1100CCC606 /* Frameworks */, 63 | 186F7B7518FAEC1100CCC606 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | 186F7B7518FAEC1100CCC606 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 186F7B7418FAEC1100CCC606 /* SCSiriWaveformView.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | 186F7B7618FAEC1100CCC606 /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 186F7BAF18FAEC6A00CCC606 /* AVFoundation.framework */, 79 | 186F7B7718FAEC1100CCC606 /* Foundation.framework */, 80 | 186F7B7918FAEC1100CCC606 /* CoreGraphics.framework */, 81 | 186F7B7B18FAEC1100CCC606 /* UIKit.framework */, 82 | ); 83 | name = Frameworks; 84 | sourceTree = ""; 85 | }; 86 | 186F7B7D18FAEC1100CCC606 /* Demo */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 186F7B8618FAEC1100CCC606 /* SCAppDelegate.h */, 90 | 186F7B8718FAEC1100CCC606 /* SCAppDelegate.m */, 91 | 186F7B8918FAEC1100CCC606 /* Main_iPad.storyboard */, 92 | 186F7BF518FAF5B500CCC606 /* Main_iPhone.storyboard */, 93 | 186F7B8C18FAEC1100CCC606 /* SCViewController.h */, 94 | 186F7B8D18FAEC1100CCC606 /* SCViewController.m */, 95 | 186F7B7E18FAEC1100CCC606 /* Supporting Files */, 96 | ); 97 | name = Demo; 98 | path = SCSiriWaveformView; 99 | sourceTree = ""; 100 | }; 101 | 186F7B7E18FAEC1100CCC606 /* Supporting Files */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 186F7B8318FAEC1100CCC606 /* main.m */, 105 | 18EF32401B2479B600204641 /* sample.m4a */, 106 | 186F7B7F18FAEC1100CCC606 /* SCSiriWaveformView-Info.plist */, 107 | ); 108 | name = "Supporting Files"; 109 | sourceTree = ""; 110 | }; 111 | 186F7BF718FAF77500CCC606 /* SCSiriWaveformView */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 186F7BF818FAF77500CCC606 /* SCSiriWaveformView.h */, 115 | 186F7BF918FAF77500CCC606 /* SCSiriWaveformView.m */, 116 | ); 117 | name = SCSiriWaveformView; 118 | path = ../SCSiriWaveformView; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | 186F7B7318FAEC1100CCC606 /* SCSiriWaveformView */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = 186F7BA618FAEC1100CCC606 /* Build configuration list for PBXNativeTarget "SCSiriWaveformView" */; 127 | buildPhases = ( 128 | 186F7B7018FAEC1100CCC606 /* Sources */, 129 | 186F7B7118FAEC1100CCC606 /* Frameworks */, 130 | 186F7B7218FAEC1100CCC606 /* Resources */, 131 | ); 132 | buildRules = ( 133 | ); 134 | dependencies = ( 135 | ); 136 | name = SCSiriWaveformView; 137 | productName = SCSiriWaveformView; 138 | productReference = 186F7B7418FAEC1100CCC606 /* SCSiriWaveformView.app */; 139 | productType = "com.apple.product-type.application"; 140 | }; 141 | /* End PBXNativeTarget section */ 142 | 143 | /* Begin PBXProject section */ 144 | 186F7B6C18FAEC1100CCC606 /* Project object */ = { 145 | isa = PBXProject; 146 | attributes = { 147 | CLASSPREFIX = SC; 148 | LastUpgradeCheck = 0510; 149 | ORGANIZATIONNAME = "Stefan Ceriu"; 150 | }; 151 | buildConfigurationList = 186F7B6F18FAEC1100CCC606 /* Build configuration list for PBXProject "SCSiriWaveformView" */; 152 | compatibilityVersion = "Xcode 3.2"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 0; 155 | knownRegions = ( 156 | English, 157 | en, 158 | Base, 159 | ); 160 | mainGroup = 186F7B6B18FAEC1100CCC606; 161 | productRefGroup = 186F7B7518FAEC1100CCC606 /* Products */; 162 | projectDirPath = ""; 163 | projectRoot = ""; 164 | targets = ( 165 | 186F7B7318FAEC1100CCC606 /* SCSiriWaveformView */, 166 | ); 167 | }; 168 | /* End PBXProject section */ 169 | 170 | /* Begin PBXResourcesBuildPhase section */ 171 | 186F7B7218FAEC1100CCC606 /* Resources */ = { 172 | isa = PBXResourcesBuildPhase; 173 | buildActionMask = 2147483647; 174 | files = ( 175 | 186F7BF618FAF5B500CCC606 /* Main_iPhone.storyboard in Resources */, 176 | 18EF32411B2479B600204641 /* sample.m4a in Resources */, 177 | 186F7B8B18FAEC1100CCC606 /* Main_iPad.storyboard in Resources */, 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | /* End PBXResourcesBuildPhase section */ 182 | 183 | /* Begin PBXSourcesBuildPhase section */ 184 | 186F7B7018FAEC1100CCC606 /* Sources */ = { 185 | isa = PBXSourcesBuildPhase; 186 | buildActionMask = 2147483647; 187 | files = ( 188 | 186F7B8818FAEC1100CCC606 /* SCAppDelegate.m in Sources */, 189 | 186F7B8E18FAEC1100CCC606 /* SCViewController.m in Sources */, 190 | 186F7BFA18FAF77500CCC606 /* SCSiriWaveformView.m in Sources */, 191 | 186F7B8418FAEC1100CCC606 /* main.m in Sources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXSourcesBuildPhase section */ 196 | 197 | /* Begin PBXVariantGroup section */ 198 | 186F7B8918FAEC1100CCC606 /* Main_iPad.storyboard */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | 186F7B8A18FAEC1100CCC606 /* Base */, 202 | ); 203 | name = Main_iPad.storyboard; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXVariantGroup section */ 207 | 208 | /* Begin XCBuildConfiguration section */ 209 | 186F7BA418FAEC1100CCC606 /* Debug */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_WARN_BOOL_CONVERSION = YES; 218 | CLANG_WARN_CONSTANT_CONVERSION = YES; 219 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 220 | CLANG_WARN_EMPTY_BODY = YES; 221 | CLANG_WARN_ENUM_CONVERSION = YES; 222 | CLANG_WARN_INT_CONVERSION = YES; 223 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 226 | COPY_PHASE_STRIP = NO; 227 | GCC_C_LANGUAGE_STANDARD = gnu99; 228 | GCC_DYNAMIC_NO_PIC = NO; 229 | GCC_OPTIMIZATION_LEVEL = 0; 230 | GCC_PREPROCESSOR_DEFINITIONS = ( 231 | "DEBUG=1", 232 | "$(inherited)", 233 | ); 234 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 237 | GCC_WARN_UNDECLARED_SELECTOR = YES; 238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 239 | GCC_WARN_UNUSED_FUNCTION = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 242 | ONLY_ACTIVE_ARCH = YES; 243 | SDKROOT = iphoneos; 244 | TARGETED_DEVICE_FAMILY = 2; 245 | }; 246 | name = Debug; 247 | }; 248 | 186F7BA518FAEC1100CCC606 /* Release */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ALWAYS_SEARCH_USER_PATHS = NO; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_WARN_BOOL_CONVERSION = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 259 | CLANG_WARN_EMPTY_BODY = YES; 260 | CLANG_WARN_ENUM_CONVERSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = YES; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 269 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 270 | GCC_WARN_UNDECLARED_SELECTOR = YES; 271 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 272 | GCC_WARN_UNUSED_FUNCTION = YES; 273 | GCC_WARN_UNUSED_VARIABLE = YES; 274 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 275 | SDKROOT = iphoneos; 276 | TARGETED_DEVICE_FAMILY = 2; 277 | VALIDATE_PRODUCT = YES; 278 | }; 279 | name = Release; 280 | }; 281 | 186F7BA718FAEC1100CCC606 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 285 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 286 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 287 | GCC_PREFIX_HEADER = ""; 288 | INFOPLIST_FILE = "SCSiriWaveformView/SCSiriWaveformView-Info.plist"; 289 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 290 | PRODUCT_NAME = "$(TARGET_NAME)"; 291 | TARGETED_DEVICE_FAMILY = "1,2"; 292 | WRAPPER_EXTENSION = app; 293 | }; 294 | name = Debug; 295 | }; 296 | 186F7BA818FAEC1100CCC606 /* Release */ = { 297 | isa = XCBuildConfiguration; 298 | buildSettings = { 299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 300 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 301 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 302 | GCC_PREFIX_HEADER = ""; 303 | INFOPLIST_FILE = "SCSiriWaveformView/SCSiriWaveformView-Info.plist"; 304 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 305 | PRODUCT_NAME = "$(TARGET_NAME)"; 306 | TARGETED_DEVICE_FAMILY = "1,2"; 307 | WRAPPER_EXTENSION = app; 308 | }; 309 | name = Release; 310 | }; 311 | /* End XCBuildConfiguration section */ 312 | 313 | /* Begin XCConfigurationList section */ 314 | 186F7B6F18FAEC1100CCC606 /* Build configuration list for PBXProject "SCSiriWaveformView" */ = { 315 | isa = XCConfigurationList; 316 | buildConfigurations = ( 317 | 186F7BA418FAEC1100CCC606 /* Debug */, 318 | 186F7BA518FAEC1100CCC606 /* Release */, 319 | ); 320 | defaultConfigurationIsVisible = 0; 321 | defaultConfigurationName = Release; 322 | }; 323 | 186F7BA618FAEC1100CCC606 /* Build configuration list for PBXNativeTarget "SCSiriWaveformView" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | 186F7BA718FAEC1100CCC606 /* Debug */, 327 | 186F7BA818FAEC1100CCC606 /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | /* End XCConfigurationList section */ 333 | }; 334 | rootObject = 186F7B6C18FAEC1100CCC606 /* Project object */; 335 | } 336 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/Base.lproj/Main_iPad.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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/Main_iPhone.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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/SCAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCAppDelegate.h 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 13/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SCAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/SCAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCAppDelegate.m 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 13/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import "SCAppDelegate.h" 10 | 11 | @implementation SCAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/SCSiriWaveformView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.stefanceriu.${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 | NSMicrophoneUsageDescription 28 | Application will use microphone to record audio. 29 | UIMainStoryboardFile 30 | Main_iPhone 31 | UIMainStoryboardFile~ipad 32 | Main_iPhone 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/SCViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCViewController.h 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 13/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SCViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/SCViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCViewController.m 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 13/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import "SCViewController.h" 10 | 11 | #import 12 | 13 | #import "SCSiriWaveformView.h" 14 | 15 | typedef NS_ENUM(NSUInteger, SCSiriWaveformViewInputType) { 16 | SCSiriWaveformViewInputTypeRecorder, 17 | SCSiriWaveformViewInputTypePlayer 18 | }; 19 | 20 | @interface SCViewController () 21 | 22 | @property (nonatomic, strong) AVAudioRecorder *recorder; 23 | @property (nonatomic, strong) AVAudioPlayer *player; 24 | 25 | @property (nonatomic, weak) IBOutlet SCSiriWaveformView *waveformView; 26 | 27 | @property (nonatomic, assign) SCSiriWaveformViewInputType selectedInputType; 28 | 29 | @end 30 | 31 | @implementation SCViewController 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | 37 | NSDictionary *settings = @{AVSampleRateKey: [NSNumber numberWithFloat: 44100.0], 38 | AVFormatIDKey: [NSNumber numberWithInt: kAudioFormatAppleLossless], 39 | AVNumberOfChannelsKey: [NSNumber numberWithInt: 2], 40 | AVEncoderAudioQualityKey: [NSNumber numberWithInt: AVAudioQualityMin]}; 41 | 42 | NSError *error; 43 | NSURL *url = [NSURL fileURLWithPath:@"/dev/null"]; 44 | self.recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error]; 45 | 46 | if(error) { 47 | NSLog(@"Ups, could not create recorder %@", error); 48 | return; 49 | } 50 | 51 | self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"sample" withExtension:@"m4a"] error:&error]; 52 | if(error) { 53 | NSLog(@"Ups, could not create player %@", error); 54 | return; 55 | } 56 | 57 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 58 | 59 | if (error) { 60 | NSLog(@"Error setting category: %@", [error description]); 61 | return; 62 | } 63 | 64 | CADisplayLink *displaylink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMeters)]; 65 | [displaylink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 66 | 67 | [self.waveformView setWaveColor:[UIColor whiteColor]]; 68 | [self.waveformView setPrimaryWaveLineWidth:3.0f]; 69 | [self.waveformView setSecondaryWaveLineWidth:1.0]; 70 | 71 | [self setSelectedInputType:SCSiriWaveformViewInputTypeRecorder]; 72 | } 73 | 74 | - (void)setSelectedInputType:(SCSiriWaveformViewInputType)selectedInputType 75 | { 76 | _selectedInputType = selectedInputType; 77 | 78 | switch (selectedInputType) { 79 | case SCSiriWaveformViewInputTypeRecorder: { 80 | [self.player stop]; 81 | 82 | [self.recorder prepareToRecord]; 83 | [self.recorder setMeteringEnabled:YES]; 84 | [self.recorder record]; 85 | break; 86 | } 87 | case SCSiriWaveformViewInputTypePlayer: { 88 | [self.recorder stop]; 89 | 90 | [self.player prepareToPlay]; 91 | [self.player setMeteringEnabled:YES]; 92 | [self.player play]; 93 | break; 94 | } 95 | } 96 | } 97 | 98 | - (IBAction)onSegmentedControlValueChanged:(UISegmentedControl *)sender 99 | { 100 | [self setSelectedInputType:(SCSiriWaveformViewInputType)sender.selectedSegmentIndex]; 101 | } 102 | 103 | - (void)updateMeters 104 | { 105 | CGFloat normalizedValue; 106 | switch (self.selectedInputType) { 107 | case SCSiriWaveformViewInputTypeRecorder: { 108 | [self.recorder updateMeters]; 109 | normalizedValue = [self _normalizedPowerLevelFromDecibels:[self.recorder averagePowerForChannel:0]]; 110 | break; 111 | } 112 | case SCSiriWaveformViewInputTypePlayer: { 113 | [self.player updateMeters]; 114 | normalizedValue = [self _normalizedPowerLevelFromDecibels:[self.player averagePowerForChannel:0]]; 115 | break; 116 | } 117 | } 118 | 119 | [self.waveformView updateWithLevel:normalizedValue]; 120 | } 121 | 122 | #pragma mark - Private 123 | 124 | - (CGFloat)_normalizedPowerLevelFromDecibels:(CGFloat)decibels 125 | { 126 | if (decibels < -60.0f || decibels == 0.0f) { 127 | return 0.0f; 128 | } 129 | 130 | return powf((powf(10.0f, 0.05f * decibels) - powf(10.0f, 0.05f * -60.0f)) * (1.0f / (1.0f - powf(10.0f, 0.05f * -60.0f))), 1.0f / 2.0f); 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 13/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "SCAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([SCAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Demo/SCSiriWaveformView/sample.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanceriu/SCSiriWaveformView/e57c1344220cd96a6c1adadafd1e7d80e1585f1d/Demo/SCSiriWaveformView/sample.m4a -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) [2013] [Stefan Ceriu] 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SCSiriWaveformView 2 | 3 | UIView subclass that reproduces the waveform effect seen in Siri on iOS 7. 4 | 5 | ##### Screenshots 6 | 7 | ![SCSiriWaveformView](https://drive.google.com/u/0/uc?id=11hLNRss__lq1IT2o6CLP0UpbYR6mbbAI&export=download) 8 | 9 | ### Usage 10 | 11 | Check out the demo project for details. 12 | 13 | ### Attributions 14 | A big thanks goes out to [Raffael Hannemann](https://twitter.com/raffael_me/) for his [SISinusWaveView](https://github.com/raffael/SISinusWaveView) 15 | 16 | ### Third Party Bindings 17 | 18 | #### React Native 19 | You may now use this library with [React Native](https://github.com/facebook/react-native) via the module [here](https://github.com/prscX/react-native-siri-wave-view) 20 | 21 | 22 | ### License 23 | SCSiriWaveformView is released under the MIT License (MIT) (see the LICENSE file) 24 | 25 | ### Contact 26 | Any suggestions or improvements are more than welcome.
27 | Feel free to contact me at [stefan.ceriu@gmail.com](mailto:stefan.ceriu@gmail.com) or [@stefanceriu](https://twitter.com/stefanceriu). 28 | -------------------------------------------------------------------------------- /SCSiriWaveformView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SCSiriWaveformView' 3 | s.version = '1.1.2' 4 | s.platform = :ios 5 | s.ios.deployment_target = '11.0' 6 | 7 | s.summary = 'UIView subclass that reproduces the waveform effect seen in Siri on iOS 7' 8 | s.homepage = 'https://github.com/stefanceriu/SCSiriWaveformView' 9 | s.author = { 'Stefan Ceriu' => 'stefan.ceriu@yahoo.com' } 10 | s.social_media_url = 'https://twitter.com/stefanceriu' 11 | s.source = { :git => 'https://github.com/stefanceriu/SCSiriWaveformView.git', :tag => "v#{s.version}" } 12 | s.license = { :type => 'MIT License', :file => 'LICENSE' } 13 | s.source_files = 'SCSiriWaveformView/*' 14 | s.requires_arc = true 15 | s.frameworks = 'UIKit', 'QuartzCore', 'CoreGraphics', 'Foundation', 'AVFoundation' 16 | s.screenshots = ["https://drive.google.com/uc?export=download&id=0ByLCkUO90ltoSVloLXRKSC1DbEk"] 17 | end -------------------------------------------------------------------------------- /SCSiriWaveformView/SCSiriWaveformView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCSiriWaveformView.h 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 12/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | IB_DESIGNABLE 12 | @interface SCSiriWaveformView : UIView 13 | 14 | /* 15 | * Tells the waveform to redraw itself using the given level (normalized value) 16 | */ 17 | - (void)updateWithLevel:(CGFloat)level; 18 | 19 | /* 20 | * The total number of waves 21 | * Default: 5 22 | */ 23 | @property (nonatomic, assign) NSUInteger numberOfWaves; 24 | 25 | /* 26 | * Color to use when drawing the waves 27 | * Default: white 28 | */ 29 | @property (nonatomic, strong) IBInspectable UIColor *waveColor; 30 | 31 | /* 32 | * Line width used for the proeminent wave 33 | * Default: 3.0f 34 | */ 35 | @property (nonatomic, assign) IBInspectable CGFloat primaryWaveLineWidth; 36 | 37 | /* 38 | * Line width used for all secondary waves 39 | * Default: 1.0f 40 | */ 41 | @property (nonatomic, assign) IBInspectable CGFloat secondaryWaveLineWidth; 42 | 43 | /* 44 | * The amplitude that is used when the incoming amplitude is near zero. 45 | * Setting a value greater 0 provides a more vivid visualization. 46 | * Default: 0.01 47 | */ 48 | @property (nonatomic, assign) IBInspectable CGFloat idleAmplitude; 49 | 50 | /* 51 | * The frequency of the sinus wave. The higher the value, the more sinus wave peaks you will have. 52 | * Default: 1.5 53 | */ 54 | @property (nonatomic, assign) IBInspectable CGFloat frequency; 55 | 56 | /* 57 | * The current amplitude 58 | */ 59 | @property (nonatomic, assign, readonly) IBInspectable CGFloat amplitude; 60 | 61 | /* 62 | * The lines are joined stepwise, the more dense you draw, the more CPU power is used. 63 | * Default: 5 64 | */ 65 | @property (nonatomic, assign) IBInspectable CGFloat density; 66 | 67 | /* 68 | * The phase shift that will be applied with each level setting 69 | * Change this to modify the animation speed or direction 70 | * Default: -0.15 71 | */ 72 | @property (nonatomic, assign) IBInspectable CGFloat phaseShift; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /SCSiriWaveformView/SCSiriWaveformView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCSiriWaveformView.m 3 | // SCSiriWaveformView 4 | // 5 | // Created by Stefan Ceriu on 12/04/2014. 6 | // Copyright (c) 2014 Stefan Ceriu. All rights reserved. 7 | // 8 | 9 | #import "SCSiriWaveformView.h" 10 | 11 | static const CGFloat kDefaultFrequency = 1.5f; 12 | static const CGFloat kDefaultAmplitude = 1.0f; 13 | static const CGFloat kDefaultIdleAmplitude = 0.01f; 14 | static const CGFloat kDefaultNumberOfWaves = 5.0f; 15 | static const CGFloat kDefaultPhaseShift = -0.15f; 16 | static const CGFloat kDefaultDensity = 5.0f; 17 | static const CGFloat kDefaultPrimaryLineWidth = 3.0f; 18 | static const CGFloat kDefaultSecondaryLineWidth = 1.0f; 19 | 20 | @interface SCSiriWaveformView () 21 | 22 | @property (nonatomic, assign) CGFloat phase; 23 | @property (nonatomic, assign) CGFloat amplitude; 24 | 25 | @end 26 | 27 | @implementation SCSiriWaveformView 28 | 29 | - (instancetype)initWithFrame:(CGRect)frame 30 | { 31 | if (self = [super initWithFrame:frame]) { 32 | [self setup]; 33 | } 34 | 35 | return self; 36 | } 37 | 38 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 39 | { 40 | if (self = [super initWithCoder:aDecoder]) { 41 | [self setup]; 42 | } 43 | 44 | return self; 45 | } 46 | 47 | - (void)setup 48 | { 49 | self.waveColor = [UIColor whiteColor]; 50 | 51 | self.frequency = kDefaultFrequency; 52 | 53 | self.amplitude = kDefaultAmplitude; 54 | self.idleAmplitude = kDefaultIdleAmplitude; 55 | 56 | self.numberOfWaves = kDefaultNumberOfWaves; 57 | self.phaseShift = kDefaultPhaseShift; 58 | self.density = kDefaultDensity; 59 | 60 | self.primaryWaveLineWidth = kDefaultPrimaryLineWidth; 61 | self.secondaryWaveLineWidth = kDefaultSecondaryLineWidth; 62 | } 63 | 64 | - (void)updateWithLevel:(CGFloat)level 65 | { 66 | self.phase += self.phaseShift; 67 | self.amplitude = fmax(level, self.idleAmplitude); 68 | 69 | [self setNeedsDisplay]; 70 | } 71 | 72 | // Thanks to Raffael Hannemann https://github.com/raffael/SISinusWaveView 73 | - (void)drawRect:(CGRect)rect 74 | { 75 | CGContextRef context = UIGraphicsGetCurrentContext(); 76 | CGContextClearRect(context, self.bounds); 77 | 78 | [self.backgroundColor set]; 79 | CGContextFillRect(context, rect); 80 | 81 | // We draw multiple sinus waves, with equal phases but altered amplitudes, multiplied by a parable function. 82 | for (int i = 0; i < self.numberOfWaves; i++) { 83 | CGFloat strokeLineWidth = (i == 0 ? self.primaryWaveLineWidth : self.secondaryWaveLineWidth); 84 | CGContextSetLineWidth(context, strokeLineWidth); 85 | 86 | CGFloat halfHeight = CGRectGetHeight(self.bounds) / 2.0f; 87 | CGFloat width = CGRectGetWidth(self.bounds); 88 | CGFloat mid = width / 2.0f; 89 | 90 | const CGFloat maxAmplitude = halfHeight - (strokeLineWidth * 2); 91 | 92 | CGFloat progress = 1.0f - (CGFloat)i / self.numberOfWaves; 93 | CGFloat normedAmplitude = (1.5f * progress - (2.0f / self.numberOfWaves)) * self.amplitude; 94 | 95 | CGFloat multiplier = MIN(1.0, (progress / 3.0f * 2.0f) + (1.0f / 3.0f)); 96 | [[self.waveColor colorWithAlphaComponent:multiplier * CGColorGetAlpha(self.waveColor.CGColor)] set]; 97 | 98 | for (CGFloat x = 0; x < (width + self.density); x += self.density) { 99 | // We use a parable to scale the sinus wave, that has its peak in the middle of the view. 100 | CGFloat scaling = -pow(1 / mid * (x - mid), 2) + 1; 101 | 102 | CGFloat y = scaling * maxAmplitude * normedAmplitude * sinf(2 * M_PI *(x / width) * self.frequency + self.phase) + halfHeight; 103 | 104 | if (x == 0) { 105 | CGContextMoveToPoint(context, x, y); 106 | } else { 107 | CGContextAddLineToPoint(context, x, y); 108 | } 109 | } 110 | 111 | CGContextStrokePath(context); 112 | } 113 | } 114 | 115 | @end 116 | --------------------------------------------------------------------------------