├── .DS_Store ├── .gitignore ├── IQAudioRecorderController Demo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IQAudioRecorderController Demo.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IQAudioRecorderController Demo ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Color Picker TextField │ ├── ColorPickerTextField.h │ ├── ColorPickerTextField.m │ ├── HFColorPicker │ │ ├── HFColorButton.h │ │ ├── HFColorButton.m │ │ ├── HFColorPickerView.h │ │ └── HFColorPickerView.m │ ├── UIColor+HexColors.h │ └── UIColor+HexColors.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x-1.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-72.png │ │ ├── Icon-72@2x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-Small-1.png │ │ ├── Icon-Small-50.png │ │ ├── Icon-Small-50@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x-1.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon-Spotlight-40.png │ │ ├── Icon-Spotlight-40@2x-1.png │ │ ├── Icon-Spotlight-40@2x.png │ │ ├── Icon-Spotlight-40@3x.png │ │ ├── Icon.png │ │ └── Icon@2x.png │ ├── Contents.json │ └── icon.imageset │ │ ├── Contents.json │ │ └── Icon-76@2x.png ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── IQAudioRecorderController.podspec.json ├── IQAudioRecorderController ├── .DS_Store ├── FDWaveformView │ ├── IQ_FDWaveformView.h │ └── IQ_FDWaveformView.m ├── IQAudioCropperViewController.h ├── IQAudioCropperViewController.m ├── IQAudioRecorderConstants.h ├── IQAudioRecorderConstants.m ├── IQAudioRecorderViewController.h ├── IQAudioRecorderViewController.m ├── IQCropSelectionBeginView.h ├── IQCropSelectionBeginView.m ├── IQCropSelectionEndView.h ├── IQCropSelectionEndView.m ├── IQCropSelectionView.h ├── IQCropSelectionView.m ├── IQMessageDisplayView.h ├── IQMessageDisplayView.m ├── IQPlaybackDurationView.h ├── IQPlaybackDurationView.m ├── NSString+IQTimeIntervalFormatter.h ├── NSString+IQTimeIntervalFormatter.m └── Resources │ ├── .DS_Store │ └── IQAudioRecorderController.bundle │ ├── audio_record.png │ ├── audio_record@2x.png │ ├── audio_record@3x.png │ ├── microphone_access.png │ ├── microphone_access@2x.png │ ├── microphone_access@3x.png │ ├── scissor.png │ ├── scissor@2x.png │ ├── scissor@3x.png │ ├── stop_playing.png │ ├── stop_playing@2x.png │ ├── stop_playing@3x.png │ ├── stop_recording.png │ ├── stop_recording@2x.png │ └── stop_recording@3x.png ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── Headers │ ├── Private │ │ ├── IQAudioRecorderController │ │ │ ├── IQAudioCropperViewController.h │ │ │ ├── IQAudioRecorderViewController.h │ │ │ ├── IQCropSelectionBeginView.h │ │ │ ├── IQCropSelectionEndView.h │ │ │ ├── IQCropSelectionView.h │ │ │ ├── IQMessageDisplayView.h │ │ │ ├── IQPlaybackDurationView.h │ │ │ ├── IQ_FDWaveformView.h │ │ │ └── NSString+IQTimeIntervalFormatter.h │ │ └── SCSiriWaveformView │ │ │ └── SCSiriWaveformView.h │ └── Public │ │ ├── IQAudioRecorderController │ │ ├── IQAudioCropperViewController.h │ │ └── IQAudioRecorderViewController.h │ │ └── SCSiriWaveformView │ │ └── SCSiriWaveformView.h ├── Local Podspecs │ └── IQAudioRecorderController.podspec.json ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── SCSiriWaveformView │ ├── LICENSE │ ├── README.md │ └── SCSiriWaveformView │ │ ├── SCSiriWaveformView.h │ │ └── SCSiriWaveformView.m └── Target Support Files │ ├── IQAudioRecorderController │ ├── IQAudioRecorderController-dummy.m │ ├── IQAudioRecorderController-prefix.pch │ └── IQAudioRecorderController.xcconfig │ ├── Pods-IQAudioRecorderController Demo │ ├── Pods-IQAudioRecorderController Demo-acknowledgements.markdown │ ├── Pods-IQAudioRecorderController Demo-acknowledgements.plist │ ├── Pods-IQAudioRecorderController Demo-dummy.m │ ├── Pods-IQAudioRecorderController Demo-frameworks.sh │ ├── Pods-IQAudioRecorderController Demo-resources.sh │ ├── Pods-IQAudioRecorderController Demo.debug.xcconfig │ └── Pods-IQAudioRecorderController Demo.release.xcconfig │ └── SCSiriWaveformView │ ├── SCSiriWaveformView-dummy.m │ ├── SCSiriWaveformView-prefix.pch │ └── SCSiriWaveformView.xcconfig ├── README.md └── Screenshot ├── Screenshot_Cropping.jpg ├── Screenshot_Idle.jpeg ├── Screenshot_No_Access.jpeg ├── Screenshot_Playing.jpeg ├── Screenshot_Recording.jpg └── iconScreenshot.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | Pods/ 20 | 21 | # MacOS X 22 | # 23 | .DS_Store 24 | *.DS_Store 25 | **/.DS_Store 26 | 27 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 07B7D65A5935B76BCFB37257 /* libPods-IQAudioRecorderController Demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB8CAE405301A095C5B87A71 /* libPods-IQAudioRecorderController Demo.a */; }; 11 | 4C136B081F4EA3810019191A /* ColorPickerTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C136B001F4EA3810019191A /* ColorPickerTextField.m */; }; 12 | 4C136B091F4EA3810019191A /* HFColorButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C136B031F4EA3810019191A /* HFColorButton.m */; }; 13 | 4C136B0A1F4EA3810019191A /* HFColorPickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C136B051F4EA3810019191A /* HFColorPickerView.m */; }; 14 | 4C136B0B1F4EA3810019191A /* UIColor+HexColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C136B071F4EA3810019191A /* UIColor+HexColors.m */; }; 15 | 4C5E9ABB1E963A1200963C8D /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C5E9ABA1E963A1200963C8D /* AVFoundation.framework */; }; 16 | 4CF11B6D2101E54B00BA4896 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF11B6C2101E54B00BA4896 /* MediaPlayer.framework */; }; 17 | B5D474141A6A2EF200771B83 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B5D474131A6A2EF200771B83 /* main.m */; }; 18 | B5D474171A6A2EF200771B83 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B5D474161A6A2EF200771B83 /* AppDelegate.m */; }; 19 | B5D4741A1A6A2EF200771B83 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5D474191A6A2EF200771B83 /* ViewController.m */; }; 20 | B5D4741D1A6A2EF200771B83 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5D4741B1A6A2EF200771B83 /* Main.storyboard */; }; 21 | B5D4741F1A6A2EF200771B83 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5D4741E1A6A2EF200771B83 /* Images.xcassets */; }; 22 | B5D474221A6A2EF200771B83 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5D474201A6A2EF200771B83 /* LaunchScreen.xib */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 162434FCF0C697D92354CEBC /* Pods-IQAudioRecorderController Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IQAudioRecorderController Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo.release.xcconfig"; sourceTree = ""; }; 27 | 4C136AFF1F4EA3810019191A /* ColorPickerTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorPickerTextField.h; sourceTree = ""; }; 28 | 4C136B001F4EA3810019191A /* ColorPickerTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ColorPickerTextField.m; sourceTree = ""; }; 29 | 4C136B021F4EA3810019191A /* HFColorButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HFColorButton.h; sourceTree = ""; }; 30 | 4C136B031F4EA3810019191A /* HFColorButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HFColorButton.m; sourceTree = ""; }; 31 | 4C136B041F4EA3810019191A /* HFColorPickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HFColorPickerView.h; sourceTree = ""; }; 32 | 4C136B051F4EA3810019191A /* HFColorPickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HFColorPickerView.m; sourceTree = ""; }; 33 | 4C136B061F4EA3810019191A /* UIColor+HexColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+HexColors.h"; sourceTree = ""; }; 34 | 4C136B071F4EA3810019191A /* UIColor+HexColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+HexColors.m"; sourceTree = ""; }; 35 | 4C5E9ABA1E963A1200963C8D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 36 | 4CF11B6C2101E54B00BA4896 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 37 | B5142A6FB6D1BB49A7B3A76B /* Pods-IQAudioRecorderController Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IQAudioRecorderController Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo.debug.xcconfig"; sourceTree = ""; }; 38 | B5D4740E1A6A2EF200771B83 /* IQAudioRecorderController Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "IQAudioRecorderController Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | B5D474121A6A2EF200771B83 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | B5D474131A6A2EF200771B83 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | B5D474151A6A2EF200771B83 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | B5D474161A6A2EF200771B83 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | B5D474181A6A2EF200771B83 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | B5D474191A6A2EF200771B83 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | B5D4741C1A6A2EF200771B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | B5D4741E1A6A2EF200771B83 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 47 | B5D474211A6A2EF200771B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 48 | EB8CAE405301A095C5B87A71 /* libPods-IQAudioRecorderController Demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-IQAudioRecorderController Demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | B5D4740B1A6A2EF200771B83 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 4CF11B6D2101E54B00BA4896 /* MediaPlayer.framework in Frameworks */, 57 | 4C5E9ABB1E963A1200963C8D /* AVFoundation.framework in Frameworks */, 58 | 07B7D65A5935B76BCFB37257 /* libPods-IQAudioRecorderController Demo.a in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 3EE7169FBE91D488DB838955 /* Pods */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | B5142A6FB6D1BB49A7B3A76B /* Pods-IQAudioRecorderController Demo.debug.xcconfig */, 69 | 162434FCF0C697D92354CEBC /* Pods-IQAudioRecorderController Demo.release.xcconfig */, 70 | ); 71 | name = Pods; 72 | sourceTree = ""; 73 | }; 74 | 4C136AFE1F4EA3810019191A /* Color Picker TextField */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 4C136AFF1F4EA3810019191A /* ColorPickerTextField.h */, 78 | 4C136B001F4EA3810019191A /* ColorPickerTextField.m */, 79 | 4C136B011F4EA3810019191A /* HFColorPicker */, 80 | 4C136B061F4EA3810019191A /* UIColor+HexColors.h */, 81 | 4C136B071F4EA3810019191A /* UIColor+HexColors.m */, 82 | ); 83 | path = "Color Picker TextField"; 84 | sourceTree = ""; 85 | }; 86 | 4C136B011F4EA3810019191A /* HFColorPicker */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 4C136B021F4EA3810019191A /* HFColorButton.h */, 90 | 4C136B031F4EA3810019191A /* HFColorButton.m */, 91 | 4C136B041F4EA3810019191A /* HFColorPickerView.h */, 92 | 4C136B051F4EA3810019191A /* HFColorPickerView.m */, 93 | ); 94 | path = HFColorPicker; 95 | sourceTree = ""; 96 | }; 97 | 9FB013BEC106672D8C3177AD /* Frameworks */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 4CF11B6C2101E54B00BA4896 /* MediaPlayer.framework */, 101 | 4C5E9ABA1E963A1200963C8D /* AVFoundation.framework */, 102 | EB8CAE405301A095C5B87A71 /* libPods-IQAudioRecorderController Demo.a */, 103 | ); 104 | name = Frameworks; 105 | sourceTree = ""; 106 | }; 107 | B5D474051A6A2EF200771B83 = { 108 | isa = PBXGroup; 109 | children = ( 110 | B5D474101A6A2EF200771B83 /* IQAudioRecorderController Demo */, 111 | B5D4740F1A6A2EF200771B83 /* Products */, 112 | 3EE7169FBE91D488DB838955 /* Pods */, 113 | 9FB013BEC106672D8C3177AD /* Frameworks */, 114 | ); 115 | sourceTree = ""; 116 | }; 117 | B5D4740F1A6A2EF200771B83 /* Products */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | B5D4740E1A6A2EF200771B83 /* IQAudioRecorderController Demo.app */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | B5D474101A6A2EF200771B83 /* IQAudioRecorderController Demo */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 4C136AFE1F4EA3810019191A /* Color Picker TextField */, 129 | B5D474151A6A2EF200771B83 /* AppDelegate.h */, 130 | B5D474161A6A2EF200771B83 /* AppDelegate.m */, 131 | B5D474181A6A2EF200771B83 /* ViewController.h */, 132 | B5D474191A6A2EF200771B83 /* ViewController.m */, 133 | B5D4741B1A6A2EF200771B83 /* Main.storyboard */, 134 | B5D4741E1A6A2EF200771B83 /* Images.xcassets */, 135 | B5D474201A6A2EF200771B83 /* LaunchScreen.xib */, 136 | B5D474111A6A2EF200771B83 /* Supporting Files */, 137 | ); 138 | path = "IQAudioRecorderController Demo"; 139 | sourceTree = ""; 140 | }; 141 | B5D474111A6A2EF200771B83 /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | B5D474121A6A2EF200771B83 /* Info.plist */, 145 | B5D474131A6A2EF200771B83 /* main.m */, 146 | ); 147 | name = "Supporting Files"; 148 | sourceTree = ""; 149 | }; 150 | /* End PBXGroup section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | B5D4740D1A6A2EF200771B83 /* IQAudioRecorderController Demo */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = B5D474311A6A2EF200771B83 /* Build configuration list for PBXNativeTarget "IQAudioRecorderController Demo" */; 156 | buildPhases = ( 157 | 4247993A1EABC828A9227380 /* [CP] Check Pods Manifest.lock */, 158 | B5D4740A1A6A2EF200771B83 /* Sources */, 159 | B5D4740B1A6A2EF200771B83 /* Frameworks */, 160 | B5D4740C1A6A2EF200771B83 /* Resources */, 161 | 0CE21EB46E2CB4D306139DCA /* [CP] Copy Pods Resources */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | ); 167 | name = "IQAudioRecorderController Demo"; 168 | productName = "IQAudioRecorderController Demo"; 169 | productReference = B5D4740E1A6A2EF200771B83 /* IQAudioRecorderController Demo.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | B5D474061A6A2EF200771B83 /* Project object */ = { 176 | isa = PBXProject; 177 | attributes = { 178 | LastUpgradeCheck = 0900; 179 | ORGANIZATIONNAME = Iftekhar; 180 | TargetAttributes = { 181 | B5D4740D1A6A2EF200771B83 = { 182 | CreatedOnToolsVersion = 6.1; 183 | DevelopmentTeam = 7UUTF6T5P9; 184 | ProvisioningStyle = Automatic; 185 | }; 186 | }; 187 | }; 188 | buildConfigurationList = B5D474091A6A2EF200771B83 /* Build configuration list for PBXProject "IQAudioRecorderController Demo" */; 189 | compatibilityVersion = "Xcode 3.2"; 190 | developmentRegion = English; 191 | hasScannedForEncodings = 0; 192 | knownRegions = ( 193 | en, 194 | Base, 195 | ); 196 | mainGroup = B5D474051A6A2EF200771B83; 197 | productRefGroup = B5D4740F1A6A2EF200771B83 /* Products */; 198 | projectDirPath = ""; 199 | projectRoot = ""; 200 | targets = ( 201 | B5D4740D1A6A2EF200771B83 /* IQAudioRecorderController Demo */, 202 | ); 203 | }; 204 | /* End PBXProject section */ 205 | 206 | /* Begin PBXResourcesBuildPhase section */ 207 | B5D4740C1A6A2EF200771B83 /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | B5D4741D1A6A2EF200771B83 /* Main.storyboard in Resources */, 212 | B5D474221A6A2EF200771B83 /* LaunchScreen.xib in Resources */, 213 | B5D4741F1A6A2EF200771B83 /* Images.xcassets in Resources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXResourcesBuildPhase section */ 218 | 219 | /* Begin PBXShellScriptBuildPhase section */ 220 | 0CE21EB46E2CB4D306139DCA /* [CP] Copy Pods Resources */ = { 221 | isa = PBXShellScriptBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | ); 225 | inputPaths = ( 226 | "${SRCROOT}/Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-resources.sh", 227 | "${PODS_ROOT}/../IQAudioRecorderController/Resources/IQAudioRecorderController.bundle", 228 | ); 229 | name = "[CP] Copy Pods Resources"; 230 | outputPaths = ( 231 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/IQAudioRecorderController.bundle", 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | shellPath = /bin/sh; 235 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-resources.sh\"\n"; 236 | showEnvVarsInLog = 0; 237 | }; 238 | 4247993A1EABC828A9227380 /* [CP] Check Pods Manifest.lock */ = { 239 | isa = PBXShellScriptBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | ); 243 | inputPaths = ( 244 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 245 | "${PODS_ROOT}/Manifest.lock", 246 | ); 247 | name = "[CP] Check Pods Manifest.lock"; 248 | outputPaths = ( 249 | "$(DERIVED_FILE_DIR)/Pods-IQAudioRecorderController Demo-checkManifestLockResult.txt", 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | shellPath = /bin/sh; 253 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 254 | showEnvVarsInLog = 0; 255 | }; 256 | /* End PBXShellScriptBuildPhase section */ 257 | 258 | /* Begin PBXSourcesBuildPhase section */ 259 | B5D4740A1A6A2EF200771B83 /* Sources */ = { 260 | isa = PBXSourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | B5D4741A1A6A2EF200771B83 /* ViewController.m in Sources */, 264 | B5D474171A6A2EF200771B83 /* AppDelegate.m in Sources */, 265 | 4C136B091F4EA3810019191A /* HFColorButton.m in Sources */, 266 | B5D474141A6A2EF200771B83 /* main.m in Sources */, 267 | 4C136B0B1F4EA3810019191A /* UIColor+HexColors.m in Sources */, 268 | 4C136B0A1F4EA3810019191A /* HFColorPickerView.m in Sources */, 269 | 4C136B081F4EA3810019191A /* ColorPickerTextField.m in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXSourcesBuildPhase section */ 274 | 275 | /* Begin PBXVariantGroup section */ 276 | B5D4741B1A6A2EF200771B83 /* Main.storyboard */ = { 277 | isa = PBXVariantGroup; 278 | children = ( 279 | B5D4741C1A6A2EF200771B83 /* Base */, 280 | ); 281 | name = Main.storyboard; 282 | sourceTree = ""; 283 | }; 284 | B5D474201A6A2EF200771B83 /* LaunchScreen.xib */ = { 285 | isa = PBXVariantGroup; 286 | children = ( 287 | B5D474211A6A2EF200771B83 /* Base */, 288 | ); 289 | name = LaunchScreen.xib; 290 | sourceTree = ""; 291 | }; 292 | /* End PBXVariantGroup section */ 293 | 294 | /* Begin XCBuildConfiguration section */ 295 | B5D4742F1A6A2EF200771B83 /* Debug */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ALWAYS_SEARCH_USER_PATHS = NO; 299 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 300 | CLANG_CXX_LIBRARY = "libc++"; 301 | CLANG_ENABLE_MODULES = YES; 302 | CLANG_ENABLE_OBJC_ARC = YES; 303 | CLANG_MODULES_AUTOLINK = NO; 304 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 305 | CLANG_WARN_BOOL_CONVERSION = YES; 306 | CLANG_WARN_COMMA = YES; 307 | CLANG_WARN_CONSTANT_CONVERSION = YES; 308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 309 | CLANG_WARN_EMPTY_BODY = YES; 310 | CLANG_WARN_ENUM_CONVERSION = YES; 311 | CLANG_WARN_INFINITE_RECURSION = YES; 312 | CLANG_WARN_INT_CONVERSION = YES; 313 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 314 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 315 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 316 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 317 | CLANG_WARN_STRICT_PROTOTYPES = YES; 318 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 319 | CLANG_WARN_UNREACHABLE_CODE = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | CODE_SIGN_IDENTITY = "iPhone Developer: Iftekhar Qurashi (RFN29V7Q6Y)"; 322 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Iftekhar Qurashi (RFN29V7Q6Y)"; 323 | COPY_PHASE_STRIP = NO; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | ENABLE_TESTABILITY = YES; 326 | GCC_C_LANGUAGE_STANDARD = gnu99; 327 | GCC_DYNAMIC_NO_PIC = NO; 328 | GCC_NO_COMMON_BLOCKS = YES; 329 | GCC_OPTIMIZATION_LEVEL = 0; 330 | GCC_PREPROCESSOR_DEFINITIONS = ( 331 | "DEBUG=1", 332 | "$(inherited)", 333 | ); 334 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 335 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 336 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 337 | GCC_WARN_UNDECLARED_SELECTOR = YES; 338 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 339 | GCC_WARN_UNUSED_FUNCTION = YES; 340 | GCC_WARN_UNUSED_VARIABLE = YES; 341 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 342 | MTL_ENABLE_DEBUG_INFO = YES; 343 | ONLY_ACTIVE_ARCH = YES; 344 | PROVISIONING_PROFILE = ""; 345 | SDKROOT = iphoneos; 346 | }; 347 | name = Debug; 348 | }; 349 | B5D474301A6A2EF200771B83 /* Release */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_MODULES_AUTOLINK = NO; 358 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 359 | CLANG_WARN_BOOL_CONVERSION = YES; 360 | CLANG_WARN_COMMA = YES; 361 | CLANG_WARN_CONSTANT_CONVERSION = YES; 362 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 363 | CLANG_WARN_EMPTY_BODY = YES; 364 | CLANG_WARN_ENUM_CONVERSION = YES; 365 | CLANG_WARN_INFINITE_RECURSION = YES; 366 | CLANG_WARN_INT_CONVERSION = YES; 367 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 371 | CLANG_WARN_STRICT_PROTOTYPES = YES; 372 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 373 | CLANG_WARN_UNREACHABLE_CODE = YES; 374 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 375 | CODE_SIGN_IDENTITY = "iPhone Developer: Iftekhar Qurashi (RFN29V7Q6Y)"; 376 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Iftekhar Qurashi (RFN29V7Q6Y)"; 377 | COPY_PHASE_STRIP = YES; 378 | ENABLE_NS_ASSERTIONS = NO; 379 | ENABLE_STRICT_OBJC_MSGSEND = YES; 380 | GCC_C_LANGUAGE_STANDARD = gnu99; 381 | GCC_NO_COMMON_BLOCKS = YES; 382 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 383 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 384 | GCC_WARN_UNDECLARED_SELECTOR = YES; 385 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 386 | GCC_WARN_UNUSED_FUNCTION = YES; 387 | GCC_WARN_UNUSED_VARIABLE = YES; 388 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 389 | MTL_ENABLE_DEBUG_INFO = NO; 390 | PROVISIONING_PROFILE = ""; 391 | SDKROOT = iphoneos; 392 | VALIDATE_PRODUCT = YES; 393 | }; 394 | name = Release; 395 | }; 396 | B5D474321A6A2EF200771B83 /* Debug */ = { 397 | isa = XCBuildConfiguration; 398 | baseConfigurationReference = B5142A6FB6D1BB49A7B3A76B /* Pods-IQAudioRecorderController Demo.debug.xcconfig */; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | CODE_SIGN_IDENTITY = "iPhone Developer: Iftekhar Qurashi (7Z2B798BLX)"; 402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 403 | DEVELOPMENT_TEAM = 7UUTF6T5P9; 404 | INFOPLIST_FILE = "IQAudioRecorderController Demo/Info.plist"; 405 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 406 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 407 | PRODUCT_BUNDLE_IDENTIFIER = com.iftekhar.audio; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | PROVISIONING_PROFILE = ""; 410 | PROVISIONING_PROFILE_SPECIFIER = ""; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | }; 413 | name = Debug; 414 | }; 415 | B5D474331A6A2EF200771B83 /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | baseConfigurationReference = 162434FCF0C697D92354CEBC /* Pods-IQAudioRecorderController Demo.release.xcconfig */; 418 | buildSettings = { 419 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 420 | CODE_SIGN_IDENTITY = "iPhone Developer: Iftekhar Qurashi (7Z2B798BLX)"; 421 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 422 | DEVELOPMENT_TEAM = 7UUTF6T5P9; 423 | INFOPLIST_FILE = "IQAudioRecorderController Demo/Info.plist"; 424 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 425 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 426 | PRODUCT_BUNDLE_IDENTIFIER = com.iftekhar.audio; 427 | PRODUCT_NAME = "$(TARGET_NAME)"; 428 | PROVISIONING_PROFILE = ""; 429 | PROVISIONING_PROFILE_SPECIFIER = ""; 430 | TARGETED_DEVICE_FAMILY = "1,2"; 431 | }; 432 | name = Release; 433 | }; 434 | /* End XCBuildConfiguration section */ 435 | 436 | /* Begin XCConfigurationList section */ 437 | B5D474091A6A2EF200771B83 /* Build configuration list for PBXProject "IQAudioRecorderController Demo" */ = { 438 | isa = XCConfigurationList; 439 | buildConfigurations = ( 440 | B5D4742F1A6A2EF200771B83 /* Debug */, 441 | B5D474301A6A2EF200771B83 /* Release */, 442 | ); 443 | defaultConfigurationIsVisible = 0; 444 | defaultConfigurationName = Release; 445 | }; 446 | B5D474311A6A2EF200771B83 /* Build configuration list for PBXNativeTarget "IQAudioRecorderController Demo" */ = { 447 | isa = XCConfigurationList; 448 | buildConfigurations = ( 449 | B5D474321A6A2EF200771B83 /* Debug */, 450 | B5D474331A6A2EF200771B83 /* Release */, 451 | ); 452 | defaultConfigurationIsVisible = 0; 453 | defaultConfigurationName = Release; 454 | }; 455 | /* End XCConfigurationList section */ 456 | }; 457 | rootObject = B5D474061A6A2EF200771B83 /* Project object */; 458 | } 459 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // IQAudioRecorderController Demo 4 | 5 | 6 | #import 7 | 8 | @interface AppDelegate : UIResponder 9 | 10 | @property (strong, nonatomic) UIWindow *window; 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // IQAudioRecorderController Demo 4 | 5 | 6 | #import "AppDelegate.h" 7 | 8 | @interface AppDelegate () 9 | 10 | @end 11 | 12 | @implementation AppDelegate 13 | 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 | // Override point for customization after application launch. 17 | return YES; 18 | } 19 | 20 | - (void)applicationWillResignActive:(UIApplication *)application { 21 | // 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. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application { 26 | // 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. 27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 28 | } 29 | 30 | - (void)applicationWillEnterForeground:(UIApplication *)application { 31 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 32 | } 33 | 34 | - (void)applicationDidBecomeActive:(UIApplication *)application { 35 | // 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. 36 | } 37 | 38 | - (void)applicationWillTerminate:(UIApplication *)application { 39 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/ColorPickerTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // ColorPickerTextField.h 3 | // IQKeyboard 4 | // 5 | // Created by Iftekhar on 27/09/14. 6 | // Copyright (c) 2014 Iftekhar. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ColorPickerTextField; 12 | 13 | @protocol ColorPickerTextFieldDelegate 14 | 15 | @optional 16 | -(void)colorPickerTextField:(nonnull ColorPickerTextField*)textField selectedColorAttributes:(nonnull NSDictionary*)colorAttributes; 17 | 18 | @end 19 | 20 | @interface ColorPickerTextField : UITextField 21 | 22 | @property(nullable, nonatomic, strong) UIColor *selectedColor; 23 | @property(nullable, strong, nonatomic) NSDictionary *selectedColorAttributes; 24 | @property (nullable, weak, nonatomic)id delegate; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/ColorPickerTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // ColorPickerTextField.m 3 | // IQKeyboard 4 | // 5 | // Created by Iftekhar on 27/09/14. 6 | // Copyright (c) 2014 Iftekhar. All rights reserved. 7 | // 8 | 9 | #import "ColorPickerTextField.h" 10 | #import "HFColorPickerView.h" 11 | #import "HFColorButton.h" 12 | #import "UIColor+HexColors.h" 13 | 14 | @interface ColorPickerTextField () 15 | 16 | @end 17 | 18 | @implementation ColorPickerTextField 19 | { 20 | HFColorPickerView *colorPickerView; 21 | HFColorButton *circleView; 22 | } 23 | 24 | @dynamic delegate; 25 | 26 | -(BOOL)canPerformAction:(SEL)action withSender:(id)sender 27 | { 28 | return NO; 29 | // if (@selector(cut:) == action || @selector(copy:) == action || @selector(paste:) == action || @selector(select:) == action || @selector(selectAll:) == action) 30 | // { 31 | // return NO; 32 | // } 33 | // else 34 | // { 35 | // return YES; 36 | // } 37 | } 38 | 39 | 40 | +(NSArray *)colorAttributes 41 | { 42 | return @[@{@"name":@"No Color", 43 | @"color":[UIColor clearColor]}, 44 | 45 | @{@"name":@"Black", 46 | @"color":[UIColor colorWithRed:0 green:0 blue:0 alpha:1]}, 47 | 48 | @{@"name":@"Dark Gray", 49 | @"color":[UIColor colorWithRed:0.333 green:0.333 blue:0.333 alpha:1]}, 50 | 51 | @{@"name":@"Gray", 52 | @"color":[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1]}, 53 | 54 | @{@"name":@"White", 55 | @"color":[UIColor colorWithRed:1 green:1 blue:1 alpha:1.0]}, 56 | 57 | 58 | 59 | @{@"name":@"Brown", 60 | @"color":[UIColor colorWithRed:121.0/255.0f green:85.0/255.0f blue:72.0/255.0f alpha:1.0f]}, 61 | 62 | @{@"name":@"Red", 63 | @"color":[UIColor colorWithRed:244.0/255.0f green:67.0/255.0f blue:54.0/255.0f alpha:1.0f]}, 64 | 65 | @{@"name":@"Deep Orange", 66 | @"color":[UIColor colorWithRed:255.0/255.0 green:87.0/255.0 blue:34.0/255.0 alpha:1.0]}, 67 | 68 | @{@"name":@"Orange", 69 | @"color":[UIColor colorWithRed:255.0/255.0 green:152.0/255.0 blue:0.0/255.0 alpha:1.0]}, 70 | 71 | @{@"name":@"Amber", 72 | @"color":[UIColor colorWithRed:255.0/255.0 green:193.0/255.0 blue:7.0/255.0 alpha:1.0]}, 73 | 74 | 75 | 76 | @{@"name":@"Teal", 77 | @"color":[UIColor colorWithRed:0.0/255.0f green:150.0/255.0f blue:136.0/255.0f alpha:1.0f]}, 78 | 79 | @{@"name":@"Green", 80 | @"color":[UIColor colorWithRed:76.0/255.0f green:175.0/255.0f blue:80.0/255.0f alpha:1.0f]}, 81 | 82 | @{@"name":@"Light Green", 83 | @"color":[UIColor colorWithRed:139.0/255.0f green:195.0/255.0f blue:74.0/255.0f alpha:1.0f]}, 84 | 85 | @{@"name":@"Lime", 86 | @"color":[UIColor colorWithRed:205.0/255.0f green:220.0/255.0f blue:57.0/255.0f alpha:1.0f]}, 87 | 88 | @{@"name":@"Yellow", 89 | @"color":[UIColor colorWithRed:255.0/255.0f green:235.0/255.0f blue:59.0/255.0f alpha:1.0f]}, 90 | 91 | 92 | 93 | @{@"name":@"Indigo", 94 | @"color":[UIColor colorWithRed:63.0/255.0f green:81.0/255.0f blue:181.0/255.0f alpha:1.0f]}, 95 | 96 | @{@"name":@"Blue Gray", 97 | @"color":[UIColor colorWithRed:96.0/255.0f green:125.0/255.0f blue:139.0/255.0f alpha:1.0f]}, 98 | 99 | @{@"name":@"Blue", 100 | @"color":[UIColor colorWithRed:33.0/255.0f green:150.0/255.0f blue:243.0/255.0f alpha:1.0f]}, 101 | 102 | @{@"name":@"Light Blue", 103 | @"color":[UIColor colorWithRed:3.0/255.0f green:169.0/255.0f blue:244.0/255.0f alpha:1.0f]}, 104 | 105 | @{@"name":@"Cyan", 106 | @"color":[UIColor colorWithRed:0.0/255.0f green:188.0/255.0f blue:212.0/255.0f alpha:1.0f]}, 107 | 108 | 109 | 110 | @{@"name":@"Deep Purple", 111 | @"color":[UIColor colorWithRed:103.0/255.0f green:58.0/255.0f blue:183.0/255.0f alpha:1.0f]}, 112 | 113 | @{@"name":@"Purple", 114 | @"color":[UIColor colorWithRed:156.0/255.0f green:39.0/255.0f blue:176.0/255.0f alpha:1.0f]}, 115 | 116 | @{@"name":@"Pink", 117 | @"color":[UIColor colorWithRed:233.0/255.0f green:30.0/255.0f blue:99.0/255.0f alpha:1.0f]}, 118 | 119 | @{@"name":@"Tomato", 120 | @"color":[UIColor colorWithRed:255.0/255.0f green:99.0/255.0f blue:71.0/255.0f alpha:1.0f]}, 121 | 122 | @{@"name":@"Wheat", 123 | @"color":[UIColor colorWithRed:255.0/255.0f green:222.0/255.0f blue:179.0/255.0f alpha:1.0f]}, 124 | ]; 125 | } 126 | 127 | -(void)commonInit 128 | { 129 | colorPickerView = [[HFColorPickerView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 180)]; 130 | colorPickerView.layer.shadowColor = [UIColor blackColor].CGColor; 131 | colorPickerView.layer.shadowOffset = CGSizeMake(0, 1); 132 | colorPickerView.layer.shadowRadius = 2; 133 | colorPickerView.layer.shadowOpacity = 0.3; 134 | colorPickerView.backgroundColor = [UIColor clearColor]; 135 | colorPickerView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 136 | colorPickerView.delegate = self; 137 | colorPickerView.colors = [[[self class] colorAttributes] valueForKey:@"color"]; 138 | self.inputView = colorPickerView; 139 | 140 | circleView = [[HFColorButton alloc] initWithFrame:CGRectMake(0,0, 25, 25)]; 141 | circleView.selected = YES; 142 | circleView.userInteractionEnabled = NO; 143 | self.rightView = circleView; 144 | self.rightViewMode = UITextFieldViewModeAlways; 145 | self.tintColor = [UIColor clearColor]; 146 | 147 | self.selectedColor = [UIColor clearColor]; 148 | } 149 | 150 | - (instancetype)initWithFrame:(CGRect)frame 151 | { 152 | self = [super initWithFrame:frame]; 153 | if (self) { 154 | [self commonInit]; 155 | } 156 | return self; 157 | } 158 | 159 | -(void)awakeFromNib 160 | { 161 | [super awakeFromNib]; 162 | 163 | [self commonInit]; 164 | } 165 | 166 | -(void)setSelectedColor:(UIColor *)selectedColor 167 | { 168 | _selectedColor = selectedColor; 169 | 170 | NSArray *colorArray = [[self class] colorAttributes]; 171 | for (int i =0; i<[colorArray count]; i++) 172 | { 173 | NSDictionary *colorAttributes = [colorArray objectAtIndex:i]; 174 | 175 | UIColor *color = [colorAttributes objectForKey:@"color"]; 176 | 177 | if ([[color hexValue] isEqualToString:[selectedColor hexValue]] && CGColorGetAlpha(color.CGColor) == CGColorGetAlpha(selectedColor.CGColor)) 178 | { 179 | _selectedColorAttributes = colorAttributes; 180 | self.text = [colorAttributes objectForKey:@"name"]; 181 | colorPickerView.selectedIndex = i; 182 | circleView.color = color; 183 | [circleView setNeedsDisplay]; 184 | break; 185 | } 186 | } 187 | } 188 | 189 | - (void)colorPicker:(HFColorPickerView*)colorPickerView selectedColor:(UIColor*)selectedColor 190 | { 191 | self.selectedColor = selectedColor; 192 | 193 | if ([self.delegate respondsToSelector:@selector(colorPickerTextField:selectedColorAttributes:)]) 194 | { 195 | [self.delegate colorPickerTextField:self selectedColorAttributes:self.selectedColorAttributes]; 196 | } 197 | } 198 | 199 | @end 200 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/HFColorPicker/HFColorButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFColorButton.h 3 | // HFColorPickerDemo 4 | // 5 | // Created by Hendrik Frahmann on 30.04.14. 6 | // Copyright (c) 2014 Hendrik Frahmann. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HFColorButton : UIButton 12 | 13 | @property (nonatomic, strong) UIColor* color; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/HFColorPicker/HFColorButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // HFColorButton.m 3 | // HFColorPickerDemo 4 | // 5 | // Created by Hendrik Frahmann on 30.04.14. 6 | // Copyright (c) 2014 Hendrik Frahmann. All rights reserved. 7 | // 8 | 9 | #import "HFColorButton.h" 10 | 11 | @interface HFColorButton() 12 | { 13 | CGContextRef context; 14 | } 15 | @end 16 | 17 | 18 | @implementation HFColorButton 19 | 20 | @synthesize color = _color; 21 | 22 | static inline float radians(double degrees) { return degrees * M_PI / 180; } 23 | 24 | - (void)drawRect:(CGRect)rect 25 | { 26 | CGRect parentViewBounds = self.bounds; 27 | 28 | CGFloat centerX = CGRectGetWidth(parentViewBounds) / 2; 29 | CGFloat centerY = CGRectGetHeight(parentViewBounds) / 2; 30 | 31 | CGFloat radius = self.bounds.size.width / 2; 32 | 33 | // Get the graphics context and clear it 34 | if(context == nil) 35 | context = UIGraphicsGetCurrentContext(); 36 | CGContextClearRect(context, rect); 37 | 38 | CGFloat colorRadius = radius * 0.6; 39 | 40 | if(self.selected) 41 | { 42 | colorRadius = radius * 0.7; 43 | 44 | CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:1 green:1 blue:1 alpha:1.0] CGColor]); 45 | CGContextSetLineWidth(context, 5); 46 | CGContextAddArc(context, centerX, centerY, radius*0.85, radians(0), radians(360), 0); 47 | CGContextClosePath(context); 48 | CGContextStrokePath(context); 49 | } 50 | 51 | 52 | CGContextSetShadow(context, CGSizeMake(0,0), 0); 53 | 54 | if (CGColorGetAlpha(_color.CGColor) != 0.0) 55 | { 56 | CGContextSetFillColor(context, CGColorGetComponents([_color CGColor])); 57 | CGContextMoveToPoint(context, centerX, centerY); 58 | CGContextAddArc(context, centerX, centerY, colorRadius, radians(0), radians(360), 0); 59 | CGContextClosePath(context); 60 | CGContextFillPath(context); 61 | } 62 | else 63 | { 64 | CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0] CGColor]); 65 | CGContextSetLineWidth(context, 1); 66 | CGContextAddArc(context, centerX, centerY, colorRadius, radians(0), radians(360), 0); 67 | CGContextClosePath(context); 68 | CGContextStrokePath(context); 69 | } 70 | } 71 | 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/HFColorPicker/HFColorPickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFColorPickerView.h 3 | // HFColorPickerDemo 4 | // 5 | // Created by Hendrik Frahmann on 30.04.14. 6 | // Copyright (c) 2014 Hendrik Frahmann. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol HFColorPickerViewDelegate; 12 | 13 | @interface HFColorPickerView : UIView 14 | 15 | @property (nonatomic, assign) IBOutlet id delegate; 16 | @property (nonatomic, strong) NSArray* colors; 17 | @property (nonatomic) CGFloat buttonDiameter; 18 | @property (nonatomic) NSInteger selectedIndex; 19 | @property (nonatomic) NSUInteger numberOfColorsPerRow; 20 | 21 | @end 22 | 23 | 24 | @protocol HFColorPickerViewDelegate 25 | 26 | - (void)colorPicker:(HFColorPickerView*)colorPickerView selectedColor:(UIColor*)selectedColor; 27 | 28 | @end -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/HFColorPicker/HFColorPickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HFColorPickerView.m 3 | // HFColorPickerDemo 4 | // 5 | // Created by Hendrik Frahmann on 30.04.14. 6 | // Copyright (c) 2014 Hendrik Frahmann. All rights reserved. 7 | // 8 | 9 | #import "HFColorPickerView.h" 10 | #import "HFColorButton.h" 11 | 12 | @interface HFColorPickerView() 13 | 14 | @property (nonatomic, strong) NSMutableArray* colorButtons; 15 | 16 | - (void)setupColorButtons; 17 | - (void)buttonClicked:(id)sender; 18 | - (void)selectButton:(HFColorButton*)button; 19 | - (void)calculateButtonFrames; 20 | 21 | @end 22 | 23 | 24 | @implementation HFColorPickerView 25 | 26 | @synthesize colorButtons = _colorButtons; 27 | @synthesize colors = _colors; 28 | @synthesize buttonDiameter = _buttonDiameter; 29 | @synthesize selectedIndex = _selectedIndex; 30 | @synthesize numberOfColorsPerRow = _numberOfColorsPerRow; 31 | 32 | - (void)setColors:(NSArray *)colors 33 | { 34 | _colors = colors; 35 | [self setupColorButtons]; 36 | } 37 | 38 | - (void)setButtonDiameter:(CGFloat)buttonDiameter 39 | { 40 | _buttonDiameter = buttonDiameter; 41 | [self calculateButtonFrames]; 42 | } 43 | 44 | - (void)setSelectedIndex:(NSInteger)selectedIndex 45 | { 46 | if(selectedIndex >= _colorButtons.count) 47 | selectedIndex = _colorButtons.count - 1; 48 | 49 | _selectedIndex = selectedIndex; 50 | 51 | HFColorButton* button = [_colorButtons objectAtIndex:selectedIndex]; 52 | [self selectButton:button]; 53 | } 54 | 55 | - (CGFloat)buttonDiameter 56 | { 57 | if(_buttonDiameter == 0.0) 58 | _buttonDiameter = 40.0; 59 | return _buttonDiameter; 60 | } 61 | 62 | -(NSUInteger)numberOfColorsPerRow 63 | { 64 | if (_numberOfColorsPerRow == 0) 65 | _numberOfColorsPerRow = 5; 66 | 67 | return _numberOfColorsPerRow; 68 | } 69 | 70 | - (NSMutableArray*)colorButtons 71 | { 72 | if(_colorButtons == nil) 73 | _colorButtons = [NSMutableArray new]; 74 | return _colorButtons; 75 | } 76 | 77 | - (void)setupColorButtons 78 | { 79 | // remove all buttons 80 | for (HFColorButton* button in self.colorButtons) 81 | { 82 | [button removeFromSuperview]; 83 | } 84 | [_colorButtons removeAllObjects]; 85 | 86 | CGFloat buttonCount = 0; 87 | 88 | // create new buttons 89 | for (UIColor* color in _colors) 90 | { 91 | HFColorButton* button = [HFColorButton new]; 92 | [button setColor:color]; 93 | [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 94 | [button setClipsToBounds:NO]; 95 | 96 | if(buttonCount == 0) 97 | button.selected = YES; 98 | buttonCount++; 99 | 100 | [self addSubview:button]; 101 | [_colorButtons addObject:button]; 102 | } 103 | 104 | [self calculateButtonFrames]; 105 | } 106 | 107 | -(void)layoutSubviews 108 | { 109 | [self calculateButtonFrames]; 110 | } 111 | 112 | - (void)calculateButtonFrames 113 | { 114 | NSInteger buttonCount = self.colorButtons.count; 115 | 116 | NSInteger buttonsPerRow = self.numberOfColorsPerRow; 117 | if(buttonsPerRow > buttonCount) 118 | buttonsPerRow = buttonCount; 119 | 120 | NSInteger numberOfRows = ceil((CGFloat)buttonCount/(CGFloat)buttonsPerRow); 121 | 122 | CGFloat buttonWidth = self.buttonDiameter; 123 | CGFloat rowWidth = self.frame.size.width/buttonsPerRow; 124 | CGFloat rowHeight = self.frame.size.height/numberOfRows; 125 | 126 | CGFloat i = 0; 127 | CGFloat j = 0; 128 | 129 | NSInteger currentIndex = 0; 130 | for (HFColorButton* button in self.colorButtons) 131 | { 132 | button.frame = CGRectMake(0, 0, buttonWidth, buttonWidth); 133 | button.center = CGPointMake(i * rowWidth + rowWidth/2, 134 | j * rowHeight + rowHeight/2); 135 | 136 | currentIndex++; 137 | j = currentIndex/buttonsPerRow; 138 | i = currentIndex%buttonsPerRow; 139 | } 140 | } 141 | 142 | - (void)buttonClicked:(id)sender 143 | { 144 | NSInteger index = [_colorButtons indexOfObject:sender]; 145 | if(index >= 0) 146 | { 147 | [self selectButton:sender]; 148 | 149 | UIColor* color = [_colors objectAtIndex:index]; 150 | if(_delegate != nil) 151 | [_delegate colorPicker:self selectedColor:color]; 152 | } 153 | } 154 | 155 | - (void)selectButton:(HFColorButton *)aButton 156 | { 157 | for (HFColorButton* button in self.colorButtons) 158 | { 159 | button.selected = NO; 160 | } 161 | aButton.selected = YES; 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/UIColor+HexColors.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+HexColors.h 3 | // KiwiHarness 4 | // 5 | // Created by Tim Duckett on 07/09/2012. 6 | // Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (HexColors) 12 | 13 | @property(nonatomic, readonly) NSString *hexValue; 14 | @property(nonatomic, readonly) CGFloat alpha; 15 | @property(nonatomic, readonly) CGFloat red; 16 | @property(nonatomic, readonly) CGFloat green; 17 | @property(nonatomic, readonly) CGFloat blue; 18 | 19 | +(UIColor *)colorWithHexString:(NSString *)hexString; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Color Picker TextField/UIColor+HexColors.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+HexColors.m 3 | // KiwiHarness 4 | // 5 | // Created by Tim on 07/09/2012. 6 | // Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved. 7 | // 8 | 9 | #import "UIColor+HexColors.h" 10 | 11 | @implementation UIColor (HexColors) 12 | 13 | -(CGFloat)alpha 14 | { 15 | return CGColorGetAlpha(self.CGColor); 16 | } 17 | 18 | -(CGFloat)red 19 | { 20 | CGFloat red; 21 | 22 | [self getRed:&red green:NULL blue:NULL alpha:NULL]; 23 | 24 | return red; 25 | } 26 | 27 | -(CGFloat)green 28 | { 29 | CGFloat green; 30 | 31 | [self getRed:NULL green:&green blue:NULL alpha:NULL]; 32 | 33 | return green; 34 | } 35 | 36 | -(CGFloat)blue 37 | { 38 | CGFloat blue; 39 | 40 | [self getRed:NULL green:NULL blue:&blue alpha:NULL]; 41 | 42 | return blue; 43 | } 44 | 45 | +(UIColor *)colorWithHexString:(NSString *)hexString { 46 | 47 | if ([hexString length] != 6) { 48 | return nil; 49 | } 50 | 51 | // Brutal and not-very elegant test for non hex-numeric characters 52 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-fA-F|0-9]" options:0 error:NULL]; 53 | NSUInteger match = [regex numberOfMatchesInString:hexString options:NSMatchingReportCompletion range:NSMakeRange(0, [hexString length])]; 54 | 55 | if (match != 0) { 56 | return nil; 57 | } 58 | 59 | NSRange rRange = NSMakeRange(0, 2); 60 | NSString *rComponent = [hexString substringWithRange:rRange]; 61 | unsigned rVal = 0; 62 | NSScanner *rScanner = [NSScanner scannerWithString:rComponent]; 63 | [rScanner scanHexInt:&rVal]; 64 | float rRetVal = (float)rVal / 254; 65 | 66 | 67 | NSRange gRange = NSMakeRange(2, 2); 68 | NSString *gComponent = [hexString substringWithRange:gRange]; 69 | unsigned gVal = 0; 70 | NSScanner *gScanner = [NSScanner scannerWithString:gComponent]; 71 | [gScanner scanHexInt:&gVal]; 72 | float gRetVal = (float)gVal / 254; 73 | 74 | NSRange bRange = NSMakeRange(4, 2); 75 | NSString *bComponent = [hexString substringWithRange:bRange]; 76 | unsigned bVal = 0; 77 | NSScanner *bScanner = [NSScanner scannerWithString:bComponent]; 78 | [bScanner scanHexInt:&bVal]; 79 | float bRetVal = (float)bVal / 254; 80 | 81 | return [UIColor colorWithRed:rRetVal green:gRetVal blue:bRetVal alpha:1.0f]; 82 | 83 | } 84 | 85 | -(NSString *)hexValue 86 | { 87 | if (self == [UIColor whiteColor]) 88 | { 89 | // Special case, as white doesn't fall into the RGB color space 90 | return @"ffffff"; 91 | } 92 | 93 | CGFloat red; 94 | CGFloat blue; 95 | CGFloat green; 96 | CGFloat alpha; 97 | 98 | [self getRed:&red green:&green blue:&blue alpha:&alpha]; 99 | 100 | int redDec = (int)(red * 255); 101 | int greenDec = (int)(green * 255); 102 | int blueDec = (int)(blue * 255); 103 | 104 | NSString *returnString = [NSString stringWithFormat:@"%02x%02x%02x", (unsigned int)redDec, (unsigned int)greenDec, (unsigned int)blueDec]; 105 | 106 | return returnString; 107 | 108 | } 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small-1.png", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@2x.png", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "size" : "29x29", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-Small@3x.png", 29 | "scale" : "3x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-Spotlight-40@2x.png", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "size" : "40x40", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-Spotlight-40@3x.png", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "size" : "57x57", 45 | "idiom" : "iphone", 46 | "filename" : "Icon.png", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "size" : "57x57", 51 | "idiom" : "iphone", 52 | "filename" : "Icon@2x.png", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "size" : "60x60", 57 | "idiom" : "iphone", 58 | "filename" : "Icon-60@2x.png", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "60x60", 63 | "idiom" : "iphone", 64 | "filename" : "Icon-60@3x.png", 65 | "scale" : "3x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "20x20", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "20x20", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "size" : "29x29", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-Small.png", 81 | "scale" : "1x" 82 | }, 83 | { 84 | "size" : "29x29", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-Small@2x-1.png", 87 | "scale" : "2x" 88 | }, 89 | { 90 | "size" : "40x40", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-Spotlight-40.png", 93 | "scale" : "1x" 94 | }, 95 | { 96 | "size" : "40x40", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-Spotlight-40@2x-1.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "50x50", 103 | "idiom" : "ipad", 104 | "filename" : "Icon-Small-50.png", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "size" : "50x50", 109 | "idiom" : "ipad", 110 | "filename" : "Icon-Small-50@2x.png", 111 | "scale" : "2x" 112 | }, 113 | { 114 | "size" : "72x72", 115 | "idiom" : "ipad", 116 | "filename" : "Icon-72.png", 117 | "scale" : "1x" 118 | }, 119 | { 120 | "size" : "72x72", 121 | "idiom" : "ipad", 122 | "filename" : "Icon-72@2x.png", 123 | "scale" : "2x" 124 | }, 125 | { 126 | "size" : "76x76", 127 | "idiom" : "ipad", 128 | "filename" : "Icon-76.png", 129 | "scale" : "1x" 130 | }, 131 | { 132 | "size" : "76x76", 133 | "idiom" : "ipad", 134 | "filename" : "Icon-76@2x.png", 135 | "scale" : "2x" 136 | }, 137 | { 138 | "size" : "83.5x83.5", 139 | "idiom" : "ipad", 140 | "filename" : "Icon-60@3x-1.png", 141 | "scale" : "2x" 142 | }, 143 | { 144 | "idiom" : "ios-marketing", 145 | "size" : "1024x1024", 146 | "scale" : "1x" 147 | } 148 | ], 149 | "info" : { 150 | "version" : 1, 151 | "author" : "xcode" 152 | } 153 | } -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x-1.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-1.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Icon-76@2x.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/Images.xcassets/icon.imageset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController Demo/Images.xcassets/icon.imageset/Icon-76@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/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 | Audio Recorder 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.2.3 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | NSMicrophoneUsageDescription 30 | Allow us to acces microphone. 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | UIInterfaceOrientationPortraitUpsideDown 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // IQAudioRecorderController Demo 4 | 5 | 6 | #import 7 | 8 | @interface ViewController : UITableViewController 9 | 10 | 11 | @end 12 | 13 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // IQAudioRecorderController Demo 4 | 5 | 6 | #import "ViewController.h" 7 | #import 8 | #import 9 | #import 10 | #import "ColorPickerTextField.h" 11 | 12 | @interface ViewController () 13 | { 14 | IBOutlet UIBarButtonItem *buttonPlayAudio; 15 | IBOutlet UIBarButtonItem *barButtonCrop; 16 | NSString *audioFilePath; 17 | 18 | IBOutlet ColorPickerTextField *normalTintColorTextField; 19 | IBOutlet ColorPickerTextField *highlightedTintColorTextField; 20 | 21 | UIColor *normalTintColor; 22 | UIColor *highlightedTintColor; 23 | 24 | IBOutlet UITextField *textFieldTitle; 25 | IBOutlet UISwitch *switchDarkUserInterface; 26 | IBOutlet UISwitch *switchAllowsCropping; 27 | IBOutlet UISwitch *switchBlurEnabled; 28 | 29 | IBOutlet UILabel *labelMaxDuration; 30 | IBOutlet UIStepper *stepperMaxDuration; 31 | } 32 | 33 | @end 34 | 35 | @implementation ViewController 36 | 37 | - (void)viewDidLoad 38 | { 39 | [super viewDidLoad]; 40 | 41 | buttonPlayAudio.enabled = NO; 42 | barButtonCrop.enabled = NO; 43 | 44 | UIToolbar *toolbar = [[UIToolbar alloc] init]; 45 | [toolbar sizeToFit]; 46 | UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 47 | UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneAction:)]; 48 | toolbar.items = @[flexItem,doneItem]; 49 | normalTintColorTextField.inputAccessoryView = highlightedTintColorTextField.inputAccessoryView = toolbar; 50 | } 51 | 52 | - (IBAction)switchThemeAction:(UISwitch *)sender 53 | { 54 | if (sender.on) 55 | { 56 | self.navigationController.navigationBar.barStyle = UIBarStyleBlack; 57 | self.navigationController.toolbar.barStyle = UIBarStyleBlack; 58 | } 59 | else 60 | { 61 | self.navigationController.navigationBar.barStyle = UIBarStyleDefault; 62 | self.navigationController.toolbar.barStyle = UIBarStyleDefault; 63 | } 64 | } 65 | 66 | - (IBAction)stepperDurationChanged:(UIStepper *)sender { 67 | labelMaxDuration.text = [NSString stringWithFormat:@"%.0f",sender.value]; 68 | } 69 | 70 | #pragma Record 71 | 72 | - (IBAction)recordAction:(UIBarButtonItem *)sender 73 | { 74 | IQAudioRecorderViewController *controller = [[IQAudioRecorderViewController alloc] init]; 75 | controller.delegate = self; 76 | controller.title = textFieldTitle.text; 77 | controller.maximumRecordDuration = stepperMaxDuration.value; 78 | controller.allowCropping = switchAllowsCropping.on; 79 | controller.normalTintColor = normalTintColor; 80 | controller.highlightedTintColor = highlightedTintColor; 81 | 82 | if (switchDarkUserInterface.on) 83 | { 84 | controller.barStyle = UIBarStyleBlack; 85 | } 86 | else 87 | { 88 | controller.barStyle = UIBarStyleDefault; 89 | } 90 | 91 | if (switchBlurEnabled.on) 92 | { 93 | [self presentBlurredAudioRecorderViewControllerAnimated:controller]; 94 | } 95 | else 96 | { 97 | [self presentAudioRecorderViewControllerAnimated:controller]; 98 | } 99 | } 100 | 101 | -(void)audioRecorderController:(IQAudioRecorderViewController *)controller didFinishWithAudioAtPath:(NSString *)filePath 102 | { 103 | audioFilePath = filePath; 104 | buttonPlayAudio.enabled = YES; 105 | barButtonCrop.enabled = YES; 106 | 107 | [controller dismissViewControllerAnimated:YES completion:nil]; 108 | } 109 | 110 | -(void)audioRecorderControllerDidCancel:(IQAudioRecorderViewController *)controller 111 | { 112 | buttonPlayAudio.enabled = NO; 113 | barButtonCrop.enabled = NO; 114 | 115 | [controller dismissViewControllerAnimated:YES completion:nil]; 116 | } 117 | 118 | #pragma Play 119 | 120 | - (IBAction)playAction:(UIBarButtonItem *)sender 121 | { 122 | MPMoviePlayerViewController *controller = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:audioFilePath]]; 123 | [self presentMoviePlayerViewControllerAnimated:controller]; 124 | } 125 | 126 | #pragma Crop 127 | 128 | - (IBAction)cropAction:(UIBarButtonItem *)sender { 129 | 130 | IQAudioCropperViewController *controller = [[IQAudioCropperViewController alloc] initWithFilePath:audioFilePath]; 131 | controller.delegate = self; 132 | controller.title = @"Crop"; 133 | controller.normalTintColor = normalTintColor; 134 | controller.highlightedTintColor = highlightedTintColor; 135 | 136 | if (switchDarkUserInterface.on) 137 | { 138 | controller.barStyle = UIBarStyleBlack; 139 | } 140 | else 141 | { 142 | controller.barStyle = UIBarStyleDefault; 143 | } 144 | 145 | if (switchBlurEnabled.on) 146 | { 147 | [self presentBlurredAudioCropperViewControllerAnimated:controller]; 148 | } 149 | else 150 | { 151 | [self presentAudioCropperViewControllerAnimated:controller]; 152 | } 153 | } 154 | 155 | -(void)audioCropperController:(IQAudioCropperViewController *)controller didFinishWithAudioAtPath:(NSString *)filePath 156 | { 157 | audioFilePath = filePath; 158 | [controller dismissViewControllerAnimated:YES completion:nil]; 159 | } 160 | 161 | -(void)audioCropperControllerDidCancel:(IQAudioCropperViewController *)controller 162 | { 163 | [controller dismissViewControllerAnimated:YES completion:nil]; 164 | } 165 | 166 | #pragma Color Picker 167 | 168 | -(void)colorPickerTextField:(nonnull ColorPickerTextField*)textField selectedColorAttributes:(nonnull NSDictionary*)colorAttributes 169 | { 170 | if (textField.tag == 4) 171 | { 172 | normalTintColor = textField.selectedColor; 173 | } 174 | else if (textField.tag == 5) 175 | { 176 | highlightedTintColor = textField.selectedColor; 177 | } 178 | } 179 | 180 | #pragma TextField 181 | 182 | -(BOOL)textFieldShouldReturn:(UITextField *)textField 183 | { 184 | [textField resignFirstResponder]; 185 | return YES; 186 | } 187 | 188 | -(void)doneAction:(UIBarButtonItem*)item 189 | { 190 | [self.view endEditing:YES]; 191 | } 192 | 193 | @end 194 | -------------------------------------------------------------------------------- /IQAudioRecorderController Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // IQAudioRecorderController Demo 4 | 5 | #import 6 | #import "AppDelegate.h" 7 | 8 | int main(int argc, char * argv[]) { 9 | @autoreleasepool { 10 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IQAudioRecorderController.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IQAudioRecorderController", 3 | "version": "1.2.3", 4 | "source": { 5 | "git": "https://github.com/hackiftekhar/IQAudioRecorderController.git", 6 | "tag": "v1.2.3" 7 | }, 8 | "summary": "A drop-in universal library allows to record audio within the app with a nice User Interface.", 9 | "homepage": "https://github.com/hackiftekhar/IQAudioRecorderController", 10 | "license": "MIT", 11 | "authors": { 12 | "Iftekhar Qurashi": "hack.iftekhar@gmail.com" 13 | }, 14 | "platforms": { 15 | "ios": "8.0" 16 | }, 17 | "source_files": "IQAudioRecorderController/**/*.{h,m}", 18 | "public_header_files": [ 19 | "IQAudioRecorderController/IQAudioRecorderViewController.h", 20 | "IQAudioRecorderController/IQAudioCropperViewController.h", 21 | "IQAudioRecorderController/IQAudioRecorderConstants.h" 22 | ], 23 | "resources": "IQAudioRecorderController/Resources/*.*", 24 | "frameworks": [ 25 | "AVFoundation", 26 | "CoreAudio", 27 | "CoreGraphics", 28 | "CoreMotion", 29 | "Foundation", 30 | "UIKit" 31 | ], 32 | "dependencies": { 33 | "SCSiriWaveformView": [] 34 | }, 35 | "requires_arc": true 36 | } 37 | -------------------------------------------------------------------------------- /IQAudioRecorderController/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/.DS_Store -------------------------------------------------------------------------------- /IQAudioRecorderController/FDWaveformView/IQ_FDWaveformView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FDWaveformView 3 | // 4 | // Created by William Entriken on 10/6/13. 5 | // Copyright (c) 2013 William Entriken. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @protocol IQ_FDWaveformViewDelegate; 11 | 12 | /// A view for rendering audio waveforms 13 | @interface IQ_FDWaveformView : UIView 14 | 15 | /// A delegate to accept progress reporting 16 | @property (nonatomic, weak) id delegate; 17 | 18 | /// The audio file to render 19 | @property (nonatomic, strong) NSURL *audioURL; 20 | 21 | /****************************************************************/ 22 | 23 | /// The total number of audio samples in the file 24 | @property (nonatomic, assign, readonly) long int totalSamples; 25 | 26 | /// The color of the waveform 27 | @property (nonatomic, copy) UIColor *wavesColor; 28 | 29 | /****************************************************************/ 30 | 31 | /// A portion of the waveform rendering to be highlighted 32 | @property (nonatomic, assign) long int progressSamples; 33 | 34 | /// The color of the highlighted waveform (see `progressSamples` 35 | @property (nonatomic, copy) UIColor *progressColor; 36 | 37 | /****************************************************************/ 38 | 39 | /// The color of the cropped waveform 40 | @property (nonatomic, copy) UIColor *cropColor; 41 | 42 | /// crop start samples 43 | @property (nonatomic, assign) long int cropStartSamples; 44 | 45 | /// crop end samples 46 | @property (nonatomic, assign) long int cropEndSamples; 47 | 48 | /****************************************************************/ 49 | 50 | /// The first sample to render 51 | @property (nonatomic, assign) long int zoomStartSamples; 52 | 53 | /// The last sample to render 54 | @property (nonatomic, assign) long int zoomEndSamples; 55 | 56 | /// Whether to all the scrub gesture 57 | @property (nonatomic) BOOL doesAllowScrubbing; 58 | 59 | /// Whether to allow the stretch gesture 60 | @property (nonatomic) BOOL doesAllowStretch; 61 | 62 | /// Whether to allow the scroll gesture 63 | @property (nonatomic) BOOL doesAllowScroll; 64 | 65 | @end 66 | 67 | /// To receive progress updates from FDWaveformView 68 | @protocol IQ_FDWaveformViewDelegate 69 | @optional 70 | 71 | /// Rendering will begin 72 | - (void)waveformViewWillRender:(IQ_FDWaveformView *)waveformView; 73 | 74 | /// Rendering did complete 75 | - (void)waveformViewDidRender:(IQ_FDWaveformView *)waveformView; 76 | 77 | /// Rendering did failed 78 | - (void)waveformViewFailedToRender:(IQ_FDWaveformView *)waveformView; 79 | 80 | /// An audio file will be loaded 81 | - (void)waveformViewWillLoad:(IQ_FDWaveformView *)waveformView; 82 | 83 | /// An audio file was loaded 84 | - (void)waveformViewDidLoad:(IQ_FDWaveformView *)waveformView; 85 | 86 | /// The panning gesture did begin 87 | - (void)waveformDidBeginPanning:(IQ_FDWaveformView *)waveformView; 88 | 89 | /// The panning gesture did end 90 | - (void)waveformDidEndPanning:(IQ_FDWaveformView *)waveformView; 91 | @end 92 | -------------------------------------------------------------------------------- /IQAudioRecorderController/FDWaveformView/IQ_FDWaveformView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FDWaveformView 3 | // 4 | // Created by William Entriken on 10/6/13. 5 | // Copyright (c) 2013 William Entriken. All rights reserved. 6 | // 7 | 8 | 9 | // FROM http://stackoverflow.com/questions/5032775/drawing-waveform-with-avassetreader 10 | // DO SEE http://stackoverflow.com/questions/1191868/uiimageview-scaling-interpolation 11 | // see http://stackoverflow.com/questions/3514066/how-to-tint-a-transparent-png-image-in-iphone 12 | 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | 19 | #import "IQ_FDWaveformView.h" 20 | 21 | #define absX(x) ((x)<0?0-(x):(x)) 22 | #define minMaxX(x,mn,mx) ((x)<=(mn)?(mn):((x)>=(mx)?(mx):(x))) 23 | #define noiseFloor (-50.0) 24 | #define decibel(amplitude) (20.0 * log10(absX(amplitude)/32767.0)) 25 | 26 | // Drawing a larger image than needed to have it available for scrolling 27 | #define horizontalMinimumBleed 0.1 28 | #define horizontalMaximumBleed 3 29 | #define horizontalTargetBleed 0.5 30 | // Drawing more pixels than shown to get antialiasing 31 | #define horizontalMinimumOverdraw 2 32 | #define horizontalMaximumOverdraw 5 33 | #define horizontalTargetOverdraw 3 34 | #define verticalMinimumOverdraw 1 35 | #define verticalMaximumOverdraw 3 36 | #define verticalTargetOverdraw 2 37 | 38 | 39 | @interface IQ_FDWaveformView() 40 | @property (nonatomic, strong) UIImageView *image; 41 | @property (nonatomic, strong) UIImageView *highlightedImage; 42 | @property (nonatomic, strong) UIImageView *croppedImage; 43 | 44 | @property (nonatomic, strong) AVAsset *asset; 45 | @property (nonatomic, strong) AVAssetTrack *assetTrack; 46 | @property (nonatomic, assign) long int totalSamples; 47 | @property (nonatomic, assign) long int cachedStartSamples; 48 | @property (nonatomic, assign) long int cachedEndSamples; 49 | @property (nonatomic, strong) UIPinchGestureRecognizer *pinchRecognizer; 50 | @property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer; 51 | @property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer; 52 | @property BOOL renderingInProgress; 53 | @property BOOL loadingInProgress; 54 | @end 55 | 56 | @implementation IQ_FDWaveformView 57 | 58 | - (void)initialize 59 | { 60 | { 61 | self.image = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 62 | self.image.contentMode = UIViewContentModeScaleToFill; 63 | [self addSubview:self.image]; 64 | } 65 | 66 | { 67 | self.highlightedImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 68 | self.highlightedImage.contentMode = UIViewContentModeScaleToFill; 69 | [self addSubview:self.highlightedImage]; 70 | } 71 | 72 | { 73 | self.croppedImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 74 | self.croppedImage.contentMode = UIViewContentModeScaleToFill; 75 | [self addSubview:self.croppedImage]; 76 | } 77 | 78 | self.clipsToBounds = YES; 79 | 80 | self.wavesColor = [UIColor blackColor]; 81 | self.progressColor = [UIColor blueColor]; 82 | 83 | self.pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; 84 | self.pinchRecognizer.delegate = self; 85 | [self addGestureRecognizer:self.pinchRecognizer]; 86 | 87 | self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; 88 | self.panRecognizer.delegate = self; 89 | [self addGestureRecognizer:self.panRecognizer]; 90 | 91 | self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; 92 | [self addGestureRecognizer:self.tapRecognizer]; 93 | } 94 | 95 | - (instancetype)initWithCoder:(NSCoder *)aCoder 96 | { 97 | if (self = [super initWithCoder:aCoder]) 98 | [self initialize]; 99 | return self; 100 | } 101 | 102 | - (instancetype)initWithFrame:(CGRect)rect 103 | { 104 | if (self = [super initWithFrame:rect]) 105 | [self initialize]; 106 | return self; 107 | } 108 | 109 | - (void)setAudioURL:(NSURL *)audioURL 110 | { 111 | _audioURL = audioURL; 112 | self.loadingInProgress = YES; 113 | if ([self.delegate respondsToSelector:@selector(waveformViewWillLoad:)]) 114 | [self.delegate waveformViewWillLoad:self]; 115 | self.asset = [AVURLAsset URLAssetWithURL:audioURL options:nil]; 116 | self.assetTrack = [[self.asset tracksWithMediaType:AVMediaTypeAudio] firstObject]; 117 | 118 | __weak typeof(self) weakSelf = self; 119 | 120 | [self.asset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{ 121 | weakSelf.loadingInProgress = NO; 122 | if ([weakSelf.delegate respondsToSelector:@selector(waveformViewDidLoad:)]) 123 | [weakSelf.delegate waveformViewDidLoad:weakSelf]; 124 | 125 | NSError *error = nil; 126 | AVKeyValueStatus durationStatus = [weakSelf.asset statusOfValueForKey:@"duration" error:&error]; 127 | switch (durationStatus) { 128 | case AVKeyValueStatusLoaded:{ 129 | 130 | void (^threadSafeNilImage)(void) = ^{ 131 | weakSelf.image.image = nil; 132 | weakSelf.highlightedImage.image = nil; 133 | weakSelf.croppedImage.image = nil; 134 | }; 135 | 136 | if ([NSThread isMainThread]) { 137 | threadSafeNilImage(); 138 | } else { 139 | dispatch_sync(dispatch_get_main_queue(), ^{ 140 | threadSafeNilImage(); 141 | }); 142 | } 143 | 144 | NSArray *formatDesc = weakSelf.assetTrack.formatDescriptions; 145 | CMAudioFormatDescriptionRef item = (__bridge CMAudioFormatDescriptionRef)formatDesc[0]; 146 | const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(item); 147 | unsigned long int samples = asbd->mSampleRate * (float)weakSelf.asset.duration.value/weakSelf.asset.duration.timescale; 148 | self.totalSamples = weakSelf.zoomEndSamples = weakSelf.cropEndSamples = samples; 149 | self.progressSamples = weakSelf.zoomStartSamples = weakSelf.cropStartSamples = 0; 150 | 151 | void (^threadSafeUpdate)(void) = ^{ 152 | 153 | [weakSelf setNeedsDisplay]; 154 | [weakSelf setNeedsLayout]; 155 | }; 156 | 157 | if ([NSThread isMainThread]) { 158 | threadSafeUpdate(); 159 | } else { 160 | dispatch_sync(dispatch_get_main_queue(), ^{ 161 | threadSafeUpdate(); 162 | }); 163 | } 164 | 165 | break; 166 | } 167 | case AVKeyValueStatusUnknown: 168 | case AVKeyValueStatusLoading: 169 | case AVKeyValueStatusFailed: 170 | case AVKeyValueStatusCancelled: 171 | NSLog(@"IQ_FDWaveformView could not load asset: %@", error.localizedDescription); 172 | break; 173 | default: 174 | break; 175 | } 176 | }]; 177 | } 178 | 179 | - (void)setProgressSamples:(long)progressSamples 180 | { 181 | _progressSamples = progressSamples; 182 | if (self.totalSamples) { 183 | float progress = (float)self.progressSamples / self.totalSamples; 184 | 185 | __weak typeof(self) weakSelf = self; 186 | 187 | void (^threadSafeUpdate)(void) = ^{ 188 | 189 | CALayer *layer = [[CALayer alloc] init]; 190 | layer.frame = CGRectMake(0,0,weakSelf.frame.size.width*progress,weakSelf.frame.size.height); 191 | layer.backgroundColor = [[UIColor blackColor] CGColor]; 192 | weakSelf.highlightedImage.layer.mask = layer; 193 | [weakSelf setNeedsLayout]; 194 | }; 195 | 196 | if ([NSThread isMainThread]) { 197 | threadSafeUpdate(); 198 | } else { 199 | dispatch_sync(dispatch_get_main_queue(), ^{ 200 | threadSafeUpdate(); 201 | }); 202 | } 203 | } 204 | } 205 | 206 | -(void)setCropStartSamples:(long)cropStartSamples 207 | { 208 | _cropStartSamples = cropStartSamples; 209 | 210 | if (self.totalSamples) { 211 | float startProgress = (float)self.cropStartSamples / self.totalSamples; 212 | float endProgress = (float)self.cropEndSamples / self.totalSamples; 213 | 214 | __weak typeof(self) weakSelf = self; 215 | 216 | void (^threadSafeUpdate)(void) = ^{ 217 | 218 | CGRect visibleRect = CGRectMake(weakSelf.frame.size.width*startProgress,0,weakSelf.frame.size.width*(endProgress-startProgress),weakSelf.frame.size.height);; 219 | UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:weakSelf.croppedImage.bounds]; 220 | [bezierPath appendPath:[UIBezierPath bezierPathWithRect:visibleRect]]; 221 | 222 | CAShapeLayer *layer = [[CAShapeLayer alloc] init]; 223 | layer.frame = weakSelf.croppedImage.bounds; 224 | layer.fillRule = kCAFillRuleEvenOdd; 225 | layer.fillColor = [UIColor blackColor].CGColor; 226 | layer.path = bezierPath.CGPath; 227 | 228 | weakSelf.croppedImage.layer.mask = layer; 229 | [weakSelf setNeedsLayout]; 230 | }; 231 | 232 | if ([NSThread isMainThread]) { 233 | threadSafeUpdate(); 234 | } else { 235 | dispatch_sync(dispatch_get_main_queue(), ^{ 236 | threadSafeUpdate(); 237 | }); 238 | } 239 | } 240 | } 241 | 242 | -(void)setCropEndSamples:(long)cropEndSamples 243 | { 244 | _cropEndSamples = cropEndSamples; 245 | 246 | if (self.totalSamples) { 247 | float startProgress = (float)self.cropStartSamples / self.totalSamples; 248 | float endProgress = (float)self.cropEndSamples / self.totalSamples; 249 | 250 | CGRect visibleRect = CGRectMake(self.frame.size.width*startProgress,0,self.frame.size.width*(endProgress-startProgress),self.frame.size.height);; 251 | UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:self.croppedImage.bounds]; 252 | [bezierPath appendPath:[UIBezierPath bezierPathWithRect:visibleRect]]; 253 | 254 | CAShapeLayer *layer = [[CAShapeLayer alloc] init]; 255 | layer.frame = self.croppedImage.bounds; 256 | layer.fillRule = kCAFillRuleEvenOdd; 257 | layer.fillColor = [UIColor blackColor].CGColor; 258 | layer.path = bezierPath.CGPath; 259 | 260 | self.croppedImage.layer.mask = layer; 261 | [self setNeedsLayout]; 262 | } 263 | } 264 | 265 | - (void)setZoomStartSamples:(long)startSamples 266 | { 267 | _zoomStartSamples = startSamples; 268 | 269 | __weak typeof(self) weakSelf = self; 270 | 271 | void (^threadSafeUpdate)(void) = ^{ 272 | 273 | [weakSelf setNeedsDisplay]; 274 | [weakSelf setNeedsLayout]; 275 | }; 276 | 277 | if ([NSThread isMainThread]) { 278 | threadSafeUpdate(); 279 | } else { 280 | dispatch_sync(dispatch_get_main_queue(), ^{ 281 | threadSafeUpdate(); 282 | }); 283 | } 284 | } 285 | 286 | - (void)setZoomEndSamples:(long)endSamples 287 | { 288 | _zoomEndSamples = endSamples; 289 | 290 | __weak typeof(self) weakSelf = self; 291 | 292 | void (^threadSafeUpdate)(void) = ^{ 293 | 294 | [weakSelf setNeedsDisplay]; 295 | [weakSelf setNeedsLayout]; 296 | }; 297 | 298 | if ([NSThread isMainThread]) { 299 | threadSafeUpdate(); 300 | } else { 301 | dispatch_sync(dispatch_get_main_queue(), ^{ 302 | threadSafeUpdate(); 303 | }); 304 | } 305 | } 306 | 307 | - (void)layoutSubviews 308 | { 309 | [super layoutSubviews]; 310 | 311 | if (!self.assetTrack || self.renderingInProgress || self.zoomEndSamples == 0) 312 | return; 313 | 314 | unsigned long int displayRange = self.zoomEndSamples - self.zoomStartSamples; 315 | BOOL needToRender = NO; 316 | if (!self.image.image) 317 | needToRender = YES; 318 | if (self.cachedStartSamples < (unsigned long)minMaxX((float)self.zoomStartSamples - displayRange * horizontalMaximumBleed, 0, self.totalSamples)) 319 | needToRender = YES; 320 | if (self.cachedStartSamples > (unsigned long)minMaxX((float)self.zoomStartSamples - displayRange * horizontalMinimumBleed, 0, self.totalSamples)) 321 | needToRender = YES; 322 | if (self.cachedEndSamples < (unsigned long)minMaxX((float)self.zoomEndSamples + displayRange * horizontalMinimumBleed, 0, self.totalSamples)) 323 | needToRender = YES; 324 | if (self.cachedEndSamples > (unsigned long)minMaxX((float)self.zoomEndSamples + displayRange * horizontalMaximumBleed, 0, self.totalSamples)) 325 | needToRender = YES; 326 | if (self.image.image.size.width < self.frame.size.width * [UIScreen mainScreen].scale * horizontalMinimumOverdraw) 327 | needToRender = YES; 328 | if (self.image.image.size.width > self.frame.size.width * [UIScreen mainScreen].scale * horizontalMaximumOverdraw) 329 | needToRender = YES; 330 | if (self.image.image.size.height < self.frame.size.height * [UIScreen mainScreen].scale * verticalMinimumOverdraw) 331 | needToRender = YES; 332 | if (self.image.image.size.height > self.frame.size.height * [UIScreen mainScreen].scale * verticalMaximumOverdraw) 333 | needToRender = YES; 334 | if (needToRender) { 335 | 336 | __weak typeof(self) weakSelf = self; 337 | 338 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 339 | [weakSelf renderAsset]; 340 | }); 341 | return; 342 | } 343 | 344 | // We need to place the images which have samples from cachedStart..cachedEnd 345 | // inside our frame which represents startSamples..endSamples 346 | // all figures are a portion of our frame size 347 | float scaledStart = 0, scaledEnd = 1, scaledWidth = 1; 348 | if (self.cachedEndSamples > self.cachedStartSamples) { 349 | scaledStart = ((float)self.cachedStartSamples-self.zoomStartSamples)/(self.zoomEndSamples-self.zoomStartSamples); 350 | scaledEnd = ((float)self.cachedEndSamples-self.zoomStartSamples)/(self.zoomEndSamples-self.zoomStartSamples); 351 | scaledWidth = scaledEnd - scaledStart; 352 | } 353 | 354 | CGRect frame = CGRectMake(self.frame.size.width*scaledStart, 0, self.frame.size.width*scaledWidth, self.frame.size.height); 355 | self.image.frame = self.highlightedImage.frame = self.croppedImage.frame = frame; 356 | } 357 | 358 | - (void)renderAsset 359 | { 360 | if (self.renderingInProgress) 361 | return; 362 | self.renderingInProgress = YES; 363 | if ([self.delegate respondsToSelector:@selector(waveformViewWillRender:)]) 364 | [self.delegate waveformViewWillRender:self]; 365 | unsigned long int displayRange = self.zoomEndSamples - self.zoomStartSamples; 366 | unsigned long int renderStartSamples = minMaxX((long)self.zoomStartSamples - displayRange * horizontalTargetBleed, 0, self.totalSamples); 367 | unsigned long int renderEndSamples = minMaxX((long)self.zoomEndSamples + displayRange * horizontalTargetBleed, 0, self.totalSamples); 368 | 369 | __block CGFloat widthInPixels = 0; 370 | __block CGFloat heightInPixels = 0; 371 | __weak typeof(self) weakSelf = self; 372 | 373 | if ([NSThread isMainThread]) 374 | { 375 | widthInPixels = self.frame.size.width * [UIScreen mainScreen].scale * horizontalTargetOverdraw; 376 | heightInPixels = self.frame.size.height * [UIScreen mainScreen].scale * verticalTargetOverdraw; 377 | } 378 | else 379 | { 380 | dispatch_sync(dispatch_get_main_queue(), ^{ 381 | widthInPixels = weakSelf.frame.size.width * [UIScreen mainScreen].scale * horizontalTargetOverdraw; 382 | heightInPixels = weakSelf.frame.size.height * [UIScreen mainScreen].scale * verticalTargetOverdraw; 383 | }); 384 | } 385 | 386 | [IQ_FDWaveformView sliceAndDownsampleAsset:self.asset track:self.assetTrack startSamples:renderStartSamples endSamples:renderEndSamples targetSamples:widthInPixels done:^(NSData *samples, NSInteger sampleCount, Float32 sampleMax) { 387 | 388 | 389 | if (samples == nil) 390 | { 391 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 392 | 393 | weakSelf.image.image = nil; 394 | weakSelf.highlightedImage.image = nil; 395 | weakSelf.croppedImage.image = nil; 396 | weakSelf.cachedStartSamples = 0; 397 | weakSelf.cachedEndSamples = 0; 398 | weakSelf.renderingInProgress = NO; 399 | if ([weakSelf.delegate respondsToSelector:@selector(waveformViewFailedToRender:)]) 400 | [weakSelf.delegate waveformViewFailedToRender:weakSelf]; 401 | }]; 402 | } 403 | else 404 | { 405 | [weakSelf plotLogGraph:samples 406 | maximumValue:sampleMax 407 | mimimumValue:noiseFloor 408 | sampleCount:sampleCount 409 | imageHeight:heightInPixels 410 | done:^(UIImage *image, 411 | UIImage *selectedImage, 412 | UIImage *cropImage) { 413 | 414 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 415 | 416 | weakSelf.image.image = image; 417 | weakSelf.highlightedImage.image = selectedImage; 418 | weakSelf.croppedImage.image = cropImage; 419 | weakSelf.cachedStartSamples = renderStartSamples; 420 | weakSelf.cachedEndSamples = renderEndSamples; 421 | weakSelf.renderingInProgress = NO; 422 | [weakSelf setNeedsLayout]; 423 | if ([weakSelf.delegate respondsToSelector:@selector(waveformViewDidRender:)]) 424 | [weakSelf.delegate waveformViewDidRender:weakSelf]; 425 | }]; 426 | } 427 | ]; 428 | } 429 | }]; 430 | } 431 | 432 | + (void)sliceAndDownsampleAsset:(AVAsset *)songAsset 433 | track:(AVAssetTrack *)songTrack 434 | startSamples:(unsigned long int)start 435 | endSamples:(unsigned long int)end 436 | targetSamples:(unsigned long int)targetSamples 437 | done:(void(^)(NSData *samples, NSInteger sampleCount, Float32 sampleMax))done 438 | { 439 | NSError *error = nil; 440 | AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:songAsset error:&error]; 441 | reader.timeRange = CMTimeRangeMake(CMTimeMake(start, songAsset.duration.timescale), CMTimeMake((end-start), songAsset.duration.timescale)); 442 | NSDictionary *outputSettingsDict = @{AVFormatIDKey: @(kAudioFormatLinearPCM), 443 | AVLinearPCMBitDepthKey: @16, 444 | AVLinearPCMIsBigEndianKey: @NO, 445 | AVLinearPCMIsFloatKey: @NO, 446 | AVLinearPCMIsNonInterleaved: @NO}; 447 | AVAssetReaderTrackOutput *output = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:songTrack outputSettings:outputSettingsDict]; 448 | output.alwaysCopiesSampleData = NO; 449 | [reader addOutput:output]; 450 | UInt32 channelCount = 0; 451 | NSArray *formatDesc = songTrack.formatDescriptions; 452 | for(unsigned int i = 0; i < [formatDesc count]; ++i) { 453 | CMAudioFormatDescriptionRef item = (__bridge CMAudioFormatDescriptionRef)formatDesc[i]; 454 | const AudioStreamBasicDescription* fmtDesc = CMAudioFormatDescriptionGetStreamBasicDescription(item); 455 | if (!fmtDesc) return; //! 456 | channelCount = fmtDesc->mChannelsPerFrame; 457 | } 458 | 459 | UInt32 bytesPerInputSample = 2 * channelCount; 460 | Float32 sampleMax = noiseFloor; 461 | Float64 tally = 0; 462 | Float32 tallyCount = 0; 463 | 464 | NSInteger downsampleFactor = (end-start) / targetSamples; 465 | downsampleFactor = downsampleFactor<1 ? 1 : downsampleFactor; 466 | NSMutableData *fullSongData = [NSMutableData dataWithCapacity:(NSUInteger)songAsset.duration.value/downsampleFactor*2]; // 16-bit samples 467 | [reader startReading]; 468 | 469 | while (reader.status == AVAssetReaderStatusReading) { 470 | AVAssetReaderTrackOutput * trackOutput = (AVAssetReaderTrackOutput *)(reader.outputs)[0]; 471 | CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer]; 472 | if (sampleBufferRef) { 473 | CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef); 474 | size_t bufferLength = CMBlockBufferGetDataLength(blockBufferRef); 475 | void *data = malloc(bufferLength); 476 | CMBlockBufferCopyDataBytes(blockBufferRef, 0, bufferLength, data); 477 | 478 | SInt16 *samples = (SInt16 *) data; 479 | int sampleCount = (int) bufferLength / bytesPerInputSample; 480 | for (int i=0; i sample ? sampleMax : sample; 491 | [fullSongData appendBytes:&sample length:sizeof(sample)]; 492 | tally = 0; 493 | tallyCount = 0; 494 | } 495 | } 496 | CMSampleBufferInvalidate(sampleBufferRef); 497 | CFRelease(sampleBufferRef); 498 | free(data); 499 | } 500 | } 501 | 502 | // if (reader.status == AVAssetReaderStatusFailed || reader.status == AVAssetReaderStatusUnknown) 503 | // Something went wrong. Handle it. 504 | if (reader.status == AVAssetReaderStatusCompleted){ 505 | done(fullSongData, fullSongData.length/4, sampleMax); 506 | } else { 507 | done(nil, 0, 0); 508 | } 509 | } 510 | 511 | - (void)plotLogGraph:(NSData *) samplesData 512 | maximumValue:(Float32) normalizeMax 513 | mimimumValue:(Float32) normalizeMin 514 | sampleCount:(NSInteger) sampleCount 515 | imageHeight:(float) imageHeight 516 | done:(void(^)(UIImage *image, 517 | UIImage *selectedImage, 518 | UIImage *cropImage))done 519 | { 520 | Float32 *samples = (Float32 *)samplesData.bytes; 521 | 522 | // TODO: switch to a synchronous function that paints onto a given context? (for issue #2) 523 | CGSize imageSize = CGSizeMake(sampleCount, imageHeight); 524 | UIGraphicsBeginImageContext(imageSize); 525 | CGContextRef context = UIGraphicsGetCurrentContext(); 526 | CGContextSetShouldAntialias(context, NO); 527 | CGContextSetAlpha(context,1.0); 528 | CGContextSetLineWidth(context, 1.0); 529 | CGContextSetStrokeColorWithColor(context, [self.wavesColor CGColor]); 530 | 531 | float halfGraphHeight = (imageHeight / 2); 532 | float centerLeft = halfGraphHeight; 533 | float sampleAdjustmentFactor; 534 | if(normalizeMax - noiseFloor == 0){ 535 | sampleAdjustmentFactor = imageHeight / 2; 536 | }else{ 537 | sampleAdjustmentFactor = imageHeight / (normalizeMax - noiseFloor) / 2; 538 | } 539 | 540 | for (NSInteger intSample=0; intSample= 0) 581 | _zoomStartSamples = middleSamples - 1/recognizer.scale*rangeSamples/2; 582 | else 583 | _zoomStartSamples = 0; 584 | if (middleSamples + 1/recognizer.scale*rangeSamples/2 <= self.totalSamples) 585 | _zoomEndSamples = middleSamples + 1/recognizer.scale*rangeSamples/2; 586 | else 587 | _zoomEndSamples = self.totalSamples; 588 | [self setNeedsDisplay]; 589 | [self setNeedsLayout]; 590 | recognizer.scale = 1; 591 | } 592 | 593 | - (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer 594 | { 595 | CGPoint point = [recognizer translationInView:self]; 596 | NSLog(@"translation: %f", point.x); 597 | 598 | if (self.doesAllowScroll) { 599 | if (recognizer.state == UIGestureRecognizerStateBegan && [self.delegate respondsToSelector:@selector(waveformDidBeginPanning:)]) 600 | [self.delegate waveformDidBeginPanning:self]; 601 | 602 | long translationSamples = (float)(self.zoomEndSamples-self.zoomStartSamples) * point.x / self.bounds.size.width; 603 | [recognizer setTranslation:CGPointZero inView:self]; 604 | if ((float)self.zoomStartSamples - translationSamples < 0) 605 | translationSamples = (float)self.zoomStartSamples; 606 | if ((float)self.zoomEndSamples - translationSamples > self.totalSamples) 607 | translationSamples = self.zoomEndSamples - self.totalSamples; 608 | _zoomStartSamples -= translationSamples; 609 | _zoomEndSamples -= translationSamples; 610 | 611 | if (recognizer.state == UIGestureRecognizerStateEnded && [self.delegate respondsToSelector:@selector(waveformDidEndPanning:)]) 612 | [self.delegate waveformDidEndPanning:self]; 613 | 614 | [self setNeedsDisplay]; 615 | [self setNeedsLayout]; 616 | } else if (self.doesAllowScrubbing) { 617 | self.progressSamples = self.zoomStartSamples + (float)(self.zoomEndSamples-self.zoomStartSamples) * [recognizer locationInView:self].x / self.bounds.size.width; 618 | } 619 | } 620 | 621 | - (void)handleTapGesture:(UITapGestureRecognizer *)recognizer 622 | { 623 | if (self.doesAllowScrubbing) { 624 | self.progressSamples = self.zoomStartSamples + (float)(self.zoomEndSamples-self.zoomStartSamples) * [recognizer locationInView:self].x / self.bounds.size.width; 625 | } 626 | } 627 | 628 | @end 629 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQAudioCropperViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQAudioCropperViewController.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | 27 | #import "IQAudioRecorderConstants.h" 28 | 29 | @class IQAudioCropperViewController; 30 | 31 | @protocol IQAudioCropperViewControllerDelegate 32 | 33 | @required 34 | /** 35 | Returns the temporary audio filePath, you need to copy the audio file to your own location and don't rely on the filePath anymore. You need to dismiss controller from yourself. 36 | */ 37 | -(void)audioCropperController:(nonnull IQAudioCropperViewController*)controller didFinishWithAudioAtPath:(nonnull NSString*)filePath; 38 | 39 | @optional 40 | /** 41 | Optional method to determine if user taps on Cancel button. If you implement this delegate then you need to dismiss controller yourself. 42 | */ 43 | -(void)audioCropperControllerDidCancel:(nonnull IQAudioCropperViewController*)controller; 44 | 45 | @end 46 | 47 | 48 | @interface IQAudioCropperViewController : UIViewController 49 | 50 | /** 51 | Initialise with audio file path 52 | */ 53 | -(nonnull instancetype)initWithFilePath:(nonnull NSString*)audioFilePath; 54 | 55 | /** 56 | Original audio file path 57 | */ 58 | @property(nonnull, nonatomic, strong, readonly) NSString *originalAudioFilePath; 59 | 60 | /** 61 | Original audio file path 62 | */ 63 | @property(nonnull, nonatomic, strong, readonly) NSString *currentAudioFilePath; 64 | 65 | /** 66 | Title to show on navigationBar 67 | */ 68 | @property(nullable, nonatomic,copy) NSString *title; 69 | 70 | ///-------------------------- 71 | /// @name Delegate callback 72 | ///-------------------------- 73 | 74 | /** 75 | IQAudioCropperViewController delegate. 76 | */ 77 | @property(nullable, nonatomic, weak) id delegate; 78 | 79 | 80 | ///-------------------------- 81 | /// @name User Interface 82 | ///-------------------------- 83 | 84 | /** 85 | Support light and dark style UI for the user interface. If you would like to present light style then you may need to set barStyle to UIBarStyleDefault, otherwise dark style UI is the default. 86 | */ 87 | @property(nonatomic,assign) UIBarStyle barStyle; 88 | 89 | /** 90 | normalTintColor is used for showing wave tintColor while not recording, it is also used for navigationBar and toolbar tintColor. 91 | */ 92 | @property (nullable, nonatomic, strong) UIColor *normalTintColor; 93 | 94 | /** 95 | Highlighted tintColor is used when playing the recorded audio file or when recording the audio file. 96 | */ 97 | @property (nullable, nonatomic, strong) UIColor *highlightedTintColor; 98 | 99 | /** 100 | Audio format. default is IQAudioFormat_m4a. 101 | */ 102 | @property(nonatomic,assign) IQAudioFormat audioFormat; 103 | 104 | @end 105 | 106 | 107 | @interface UIViewController (IQAudioCropperViewController) 108 | 109 | - (void)presentAudioCropperViewControllerAnimated:(nonnull IQAudioCropperViewController *)audioCropperViewController; 110 | - (void)presentBlurredAudioCropperViewControllerAnimated:(nonnull IQAudioCropperViewController *)audioCropperViewController; 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQAudioRecorderConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQAudioRecorderConstants.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | #import 27 | #import 28 | 29 | typedef NS_ENUM(NSUInteger, IQAudioFormat) { 30 | IQAudioFormatDefault, // kAudioFormatMPEG4AAC .m4a 31 | IQAudioFormat_m4a = kAudioFormatMPEG4AAC, //.m4a 32 | IQAudioFormat_caf = kAudioFormatAppleLossless, //.caf 33 | IQAudioFormat_wav = kAudioFormatLinearPCM, //.wav 34 | }; 35 | 36 | typedef NS_ENUM(NSUInteger, IQAudioQuality) { 37 | IQAudioQualityDefault = -1, 38 | IQAudioQualityMin = AVAudioQualityMin, 39 | IQAudioQualityLow = AVAudioQualityLow, 40 | IQAudioQualityMedium = AVAudioQualityMedium, 41 | IQAudioQualityHigh = AVAudioQualityHigh, 42 | IQAudioQualityMax = AVAudioQualityMax, 43 | }; 44 | 45 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQAudioRecorderConstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQAudioRecorderConstants.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQAudioRecorderConstants.h" 26 | 27 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQAudioRecorderViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQAudioRecorderController.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | #import "IQAudioRecorderConstants.h" 29 | 30 | @class IQAudioRecorderViewController; 31 | 32 | @protocol IQAudioRecorderViewControllerDelegate 33 | 34 | @required 35 | /** 36 | Returns the temporary recorded filePath, you need to copy the recorded file to your own location and don't rely on the filePath anymore. You need to dismiss controller yourself. 37 | */ 38 | -(void)audioRecorderController:(nonnull IQAudioRecorderViewController*)controller didFinishWithAudioAtPath:(nonnull NSString*)filePath; 39 | 40 | @optional 41 | /** 42 | Optional method to determine if user taps on Cancel button. If you implement this delegate then you need to dismiss controller yourself. 43 | */ 44 | -(void)audioRecorderControllerDidCancel:(nonnull IQAudioRecorderViewController*)controller; 45 | 46 | @end 47 | 48 | 49 | 50 | @interface IQAudioRecorderViewController : UIViewController 51 | 52 | /** 53 | Title to show on navigationBar 54 | */ 55 | @property(nullable, nonatomic,copy) NSString *title; 56 | 57 | ///-------------------------- 58 | /// @name Delegate callback 59 | ///-------------------------- 60 | 61 | /** 62 | IQAudioRecorderController delegate. 63 | */ 64 | @property(nullable, nonatomic, weak) id delegate; 65 | 66 | 67 | ///-------------------------- 68 | /// @name User Interface 69 | ///-------------------------- 70 | 71 | /** 72 | Support light and dark style UI for the user interface. If you would like to present light style then you may need to set barStyle to UIBarStyleDefault, otherwise dark style UI is the default. 73 | */ 74 | @property(nonatomic,assign) UIBarStyle barStyle; 75 | 76 | /** 77 | normalTintColor is used for showing wave tintColor while not recording, it is also used for navigationBar and toolbar tintColor. 78 | */ 79 | @property (nullable, nonatomic, strong) UIColor *normalTintColor; 80 | 81 | /** 82 | Highlighted tintColor is used when playing the recorded audio file or when recording the audio file. 83 | */ 84 | @property (nullable, nonatomic, strong) UIColor *highlightedTintColor; 85 | 86 | /** 87 | Allows to crop audio files. 88 | */ 89 | @property (nonatomic, assign) BOOL allowCropping; 90 | 91 | 92 | ///-------------------------- 93 | /// @name Audio Settings 94 | ///-------------------------- 95 | 96 | 97 | /** 98 | Maximum duration of the audio file to be recorded. 99 | */ 100 | @property(nonatomic) NSTimeInterval maximumRecordDuration; 101 | 102 | /** 103 | Audio format. default is IQAudioFormat_m4a. 104 | */ 105 | @property(nonatomic,assign) IQAudioFormat audioFormat; 106 | 107 | /** 108 | sampleRate should be floating point in Hertz. 109 | */ 110 | @property(nonatomic,assign) CGFloat sampleRate; 111 | 112 | /** 113 | Number of channels. 114 | */ 115 | @property(nonatomic,assign) NSInteger numberOfChannels; 116 | 117 | /** 118 | Audio quality. 119 | */ 120 | @property(nonatomic,assign) IQAudioQuality audioQuality; 121 | 122 | /** 123 | bitRate. 124 | */ 125 | @property(nonatomic,assign) NSInteger bitRate; 126 | 127 | @end 128 | 129 | 130 | @interface UIViewController (IQAudioRecorderViewController) 131 | 132 | - (void)presentAudioRecorderViewControllerAnimated:(nonnull IQAudioRecorderViewController *)audioRecorderViewController; 133 | - (void)presentBlurredAudioRecorderViewControllerAnimated:(nonnull IQAudioRecorderViewController *)audioRecorderViewController; 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionBeginView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionBeginView.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQCropSelectionView.h" 26 | 27 | @interface IQCropSelectionBeginView : IQCropSelectionView 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionBeginView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionBeginView.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQCropSelectionBeginView.h" 26 | 27 | @implementation IQCropSelectionBeginView 28 | 29 | - (instancetype)initWithFrame:(CGRect)frame 30 | { 31 | self = [super initWithFrame:frame]; 32 | if (self) { 33 | timeLabel.textAlignment = NSTextAlignmentRight; 34 | } 35 | return self; 36 | } 37 | 38 | -(void)layoutSubviews 39 | { 40 | [super layoutSubviews]; 41 | 42 | static CGFloat timeLabelheight = 20; 43 | 44 | lineView.frame =CGRectMake(CGRectGetMidX(self.bounds), timeLabelheight, CGRectGetWidth(lineView.frame), CGRectGetHeight(self.bounds)-timeLabelheight*2); 45 | 46 | smallLineView.frame =CGRectMake(CGRectGetMidX(lineView.frame), CGRectGetMaxY(lineView.frame)-CGRectGetWidth(lineView.frame), CGRectGetWidth(self.bounds)/2, CGRectGetWidth(lineView.frame)); 47 | 48 | timeLabel.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), timeLabelheight); 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionEndView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionEndView.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQCropSelectionView.h" 26 | 27 | @interface IQCropSelectionEndView : IQCropSelectionView 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionEndView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionEndView.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQCropSelectionEndView.h" 26 | 27 | @implementation IQCropSelectionEndView 28 | 29 | - (instancetype)initWithFrame:(CGRect)frame 30 | { 31 | self = [super initWithFrame:frame]; 32 | if (self) { 33 | timeLabel.textAlignment = NSTextAlignmentLeft; 34 | } 35 | return self; 36 | } 37 | 38 | -(void)layoutSubviews 39 | { 40 | [super layoutSubviews]; 41 | 42 | static CGFloat timeLabelheight = 20; 43 | 44 | lineView.frame =CGRectMake(CGRectGetMidX(self.bounds), timeLabelheight, CGRectGetWidth(lineView.frame), CGRectGetHeight(self.bounds)-timeLabelheight*2); 45 | 46 | smallLineView.frame =CGRectMake(CGRectGetMinX(self.bounds), timeLabelheight, CGRectGetWidth(self.bounds)/2, CGRectGetWidth(lineView.frame)); 47 | 48 | timeLabel.frame = CGRectMake(0, CGRectGetHeight(self.bounds)-timeLabelheight, CGRectGetWidth(self.bounds), timeLabelheight); 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionView.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | 27 | @interface IQCropSelectionView : UIView 28 | { 29 | UIView *lineView; 30 | UIView *smallLineView; 31 | UILabel *timeLabel; 32 | } 33 | 34 | @property(nonatomic, assign) NSTimeInterval cropTime; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQCropSelectionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQCropSelectionView.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "IQCropSelectionView.h" 26 | #import "NSString+IQTimeIntervalFormatter.h" 27 | 28 | @implementation IQCropSelectionView 29 | 30 | - (instancetype)initWithFrame:(CGRect)frame 31 | { 32 | self = [super initWithFrame:frame]; 33 | if (self) { 34 | 35 | lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2, CGRectGetHeight(self.bounds))]; 36 | lineView.userInteractionEnabled = NO; 37 | lineView.backgroundColor = [UIColor redColor]; 38 | [self addSubview:lineView]; 39 | 40 | smallLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds)/2, CGRectGetWidth(lineView.frame))]; 41 | smallLineView.backgroundColor = [UIColor redColor]; 42 | smallLineView.userInteractionEnabled = NO; 43 | [self addSubview:smallLineView]; 44 | 45 | timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.bounds)-20, CGRectGetWidth(self.bounds), 20)]; 46 | timeLabel.textColor = [UIColor redColor]; 47 | timeLabel.minimumScaleFactor = 0.5; 48 | timeLabel.adjustsFontSizeToFitWidth = YES; 49 | timeLabel.textAlignment = NSTextAlignmentCenter; 50 | timeLabel.font = [UIFont boldSystemFontOfSize:12]; 51 | [self addSubview:timeLabel]; 52 | self.clipsToBounds = NO; 53 | } 54 | return self; 55 | } 56 | 57 | -(void)setCropTime:(NSTimeInterval)cropTime 58 | { 59 | _cropTime = cropTime; 60 | 61 | timeLabel.text = [NSString timeStringForTimeInterval:cropTime]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQMessageDisplayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQMessageDisplayView.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | @class IQMessageDisplayView; 29 | 30 | @protocol IQMessageDisplayViewDelegate 31 | 32 | @optional 33 | - (void)messageDisplayViewDidTapOnButton:(nonnull IQMessageDisplayView *)displayView; 34 | 35 | @end 36 | 37 | @interface IQMessageDisplayView : UIView 38 | 39 | @property(nullable, nonatomic, weak) IBOutlet id delegate; 40 | 41 | @property(nullable, nonatomic, strong) UIImage *image; 42 | @property(nullable, nonatomic, strong) NSString *title; 43 | @property(nullable, nonatomic, strong) NSString *message; 44 | @property(nullable, nonatomic, strong) NSString *buttonTitle; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQMessageDisplayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQMessageDisplayView.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import "IQMessageDisplayView.h" 27 | 28 | //IB_DESIGNABLE 29 | @implementation IQMessageDisplayView 30 | { 31 | UIImageView *imageView; 32 | UILabel *labelTitle; 33 | UILabel *labelMessage; 34 | UIButton *buttonAction; 35 | } 36 | 37 | - (instancetype)initWithFrame:(CGRect)frame 38 | { 39 | self = [super initWithFrame:frame]; 40 | if (self) { 41 | [self setup]; 42 | } 43 | return self; 44 | } 45 | 46 | - (instancetype)initWithCoder:(NSCoder *)coder 47 | { 48 | self = [super initWithCoder:coder]; 49 | if (self) { 50 | [self setup]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)setup 56 | { 57 | imageView = [[UIImageView alloc] init]; 58 | imageView.tintColor = [UIColor lightGrayColor]; 59 | [self addSubview:imageView]; 60 | 61 | labelTitle = [[UILabel alloc] init]; 62 | labelTitle.font = [UIFont boldSystemFontOfSize:20.0]; 63 | labelTitle.textColor = [UIColor lightGrayColor]; 64 | labelTitle.numberOfLines = 0; 65 | labelTitle.textAlignment = NSTextAlignmentCenter; 66 | [self addSubview:labelTitle]; 67 | 68 | labelMessage = [[UILabel alloc] init]; 69 | labelMessage.font = [UIFont systemFontOfSize:13.0]; 70 | labelMessage.textColor = [UIColor lightGrayColor]; 71 | labelMessage.numberOfLines = 0; 72 | labelMessage.textAlignment = NSTextAlignmentCenter; 73 | [self addSubview:labelMessage]; 74 | 75 | buttonAction = [UIButton buttonWithType:UIButtonTypeSystem]; 76 | buttonAction.enabled = NO; 77 | [buttonAction addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside]; 78 | buttonAction.titleLabel.font = [UIFont boldSystemFontOfSize:17]; 79 | [self addSubview:buttonAction]; 80 | 81 | //Constraint 82 | { 83 | imageView.translatesAutoresizingMaskIntoConstraints = NO; 84 | labelTitle.translatesAutoresizingMaskIntoConstraints = NO; 85 | labelMessage.translatesAutoresizingMaskIntoConstraints = NO; 86 | buttonAction.translatesAutoresizingMaskIntoConstraints = NO; 87 | 88 | NSDictionary *views = @{@"imageView":imageView,@"labelTitle":labelTitle,@"labelMessage":labelMessage,@"buttonAction":buttonAction}; 89 | 90 | NSMutableArray *constraints = [[NSMutableArray alloc] init]; 91 | 92 | [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[imageView]-[labelTitle]-[labelMessage]-[buttonAction]-|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]]; 93 | 94 | [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[labelTitle]-|" options:0 metrics:nil views:views]]; 95 | [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[labelMessage]-|" options:0 metrics:nil views:views]]; 96 | 97 | [self addConstraints:constraints]; 98 | } 99 | } 100 | 101 | -(void)setImage:(UIImage *)image 102 | { 103 | _image = image; 104 | imageView.image = image; 105 | } 106 | 107 | -(void)setTitle:(NSString *)title 108 | { 109 | _title = title; 110 | labelTitle.text = title; 111 | } 112 | 113 | -(void)setMessage:(NSString *)message 114 | { 115 | _message = message; 116 | labelMessage.text = message; 117 | } 118 | 119 | -(void)setButtonTitle:(NSString *)buttonTitle 120 | { 121 | _buttonTitle = buttonTitle; 122 | [buttonAction setTitle:buttonTitle forState:UIControlStateNormal]; 123 | buttonAction.enabled = buttonTitle.length; 124 | } 125 | 126 | - (void)prepareForInterfaceBuilder 127 | { 128 | NSBundle* bundle = [NSBundle bundleForClass:self.class]; 129 | if (bundle == nil) bundle = [NSBundle mainBundle]; 130 | NSBundle *resourcesBundle = [NSBundle bundleWithPath:[bundle pathForResource:@"IQAudioRecorderController" ofType:@"bundle"]]; 131 | if (resourcesBundle == nil) resourcesBundle = bundle; 132 | 133 | self.image = [UIImage imageNamed:@"microphone_access" inBundle:resourcesBundle compatibleWithTraitCollection:nil]; 134 | self.title = NSLocalizedString(@"Access Denied!",nil); 135 | self.message = NSLocalizedString(@"We are unable to access microphone due to privacy restrictions. Please enable access for microphone in Settings->Privacy Settings->Microphone",nil); 136 | self.buttonTitle = NSLocalizedString(@"Go to Settings",nil); 137 | } 138 | 139 | -(void)buttonAction:(UIButton*)button 140 | { 141 | if ([self.delegate respondsToSelector:@selector(messageDisplayViewDidTapOnButton:)]) 142 | { 143 | [self.delegate messageDisplayViewDidTapOnButton:self]; 144 | } 145 | } 146 | 147 | -(void)dealloc 148 | { 149 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 150 | } 151 | 152 | @end 153 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQPlaybackDurationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IQPlaybackDurationView.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Sebastian Ludwig 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | @class IQPlaybackDurationView; 29 | 30 | @protocol IQPlaybackDurationViewDelegate 31 | 32 | @optional 33 | - (void)playbackDurationView:(nonnull IQPlaybackDurationView *)playbackView didStartScrubbingAtTime:(NSTimeInterval)time; 34 | - (void)playbackDurationView:(nonnull IQPlaybackDurationView *)playbackView didScrubToTime:(NSTimeInterval)time; 35 | - (void)playbackDurationView:(nonnull IQPlaybackDurationView *)playbackView didEndScrubbingAtTime:(NSTimeInterval)time; 36 | 37 | @end 38 | 39 | @interface IQPlaybackDurationView : UIView 40 | 41 | @property (nullable, nonatomic, weak) IBOutlet id delegate; 42 | 43 | @property (nonatomic, getter=isShowingRemainingTime) IBInspectable BOOL showRemainingTime; 44 | 45 | @property (nonatomic, assign) NSTimeInterval duration; 46 | @property (nonatomic, assign) NSTimeInterval currentTime; 47 | 48 | - (void)setCurrentTime:(NSTimeInterval)time animated:(BOOL)animated; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /IQAudioRecorderController/IQPlaybackDurationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IQPlaybackDurationView.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Sebastian Ludwig 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import "IQPlaybackDurationView.h" 27 | #import "NSString+IQTimeIntervalFormatter.h" 28 | 29 | //IB_DESIGNABLE 30 | @implementation IQPlaybackDurationView 31 | { 32 | UISlider *_playerSlider; 33 | UILabel *_labelCurrentTime; 34 | UILabel *_labelRemainingTime; 35 | } 36 | 37 | - (CGSize )intrinsicContentSize { 38 | return UILayoutFittingExpandedSize; 39 | } 40 | 41 | - (instancetype)initWithFrame:(CGRect)frame 42 | { 43 | if (self = [super initWithFrame:frame]) { 44 | [self setup]; 45 | } 46 | return self; 47 | } 48 | 49 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 50 | { 51 | if (self = [super initWithCoder:aDecoder]) { 52 | [self setup]; 53 | } 54 | return self; 55 | } 56 | 57 | -(void)tintColorDidChange 58 | { 59 | [super tintColorDidChange]; 60 | 61 | _labelCurrentTime.textColor = self.tintColor; 62 | _labelRemainingTime.textColor = self.tintColor; 63 | _playerSlider.minimumTrackTintColor = self.tintColor; 64 | } 65 | 66 | - (void)setup 67 | { 68 | //Current Time 69 | { 70 | _labelCurrentTime = [[UILabel alloc] init]; 71 | 72 | { 73 | _labelCurrentTime.translatesAutoresizingMaskIntoConstraints = NO; 74 | [_labelCurrentTime setContentHuggingPriority:UILayoutPriorityDefaultLow+1 forAxis:UILayoutConstraintAxisHorizontal]; 75 | [_labelCurrentTime setContentHuggingPriority:UILayoutPriorityDefaultLow+1 forAxis:UILayoutConstraintAxisVertical]; 76 | } 77 | 78 | _labelCurrentTime.textColor = self.tintColor; 79 | _labelCurrentTime.text = [NSString timeStringForTimeInterval:0]; 80 | _labelCurrentTime.font = [UIFont boldSystemFontOfSize:14.0]; 81 | [self addSubview:_labelCurrentTime]; 82 | } 83 | 84 | //Player Slider 85 | { 86 | _playerSlider = [[UISlider alloc] init]; 87 | 88 | { 89 | _playerSlider.translatesAutoresizingMaskIntoConstraints = NO; 90 | [_playerSlider setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal]; 91 | [_playerSlider setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisVertical]; 92 | } 93 | 94 | _playerSlider.minimumTrackTintColor = self.tintColor; 95 | _playerSlider.value = 0; 96 | [_playerSlider addTarget:self action:@selector(sliderStart) forControlEvents:UIControlEventTouchDown]; 97 | [_playerSlider addTarget:self action:@selector(sliderMoved) forControlEvents:UIControlEventValueChanged]; 98 | [_playerSlider addTarget:self action:@selector(sliderEnd) forControlEvents:UIControlEventTouchUpInside]; 99 | [_playerSlider addTarget:self action:@selector(sliderEnd) forControlEvents:UIControlEventTouchUpOutside]; 100 | [_playerSlider addTarget:self action:@selector(sliderEnd) forControlEvents:UIControlEventTouchCancel]; 101 | [self addSubview:_playerSlider]; 102 | } 103 | 104 | //Remaining Time 105 | { 106 | _labelRemainingTime = [[UILabel alloc] init]; 107 | 108 | { 109 | _labelRemainingTime.translatesAutoresizingMaskIntoConstraints = NO; 110 | [_labelRemainingTime setContentHuggingPriority:UILayoutPriorityDefaultLow+1 forAxis:UILayoutConstraintAxisHorizontal]; 111 | [_labelRemainingTime setContentHuggingPriority:UILayoutPriorityDefaultLow+1 forAxis:UILayoutConstraintAxisVertical]; 112 | } 113 | 114 | _labelRemainingTime.textColor = self.tintColor; 115 | _labelRemainingTime.text = [NSString timeStringForTimeInterval:0]; 116 | _labelRemainingTime.userInteractionEnabled = YES; 117 | [_labelRemainingTime addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleRemainingTimeDisplay:)]]; 118 | _labelRemainingTime.font = _labelCurrentTime.font; 119 | [self addSubview:_labelRemainingTime]; 120 | } 121 | 122 | //Constraint 123 | { 124 | NSDictionary *views = @{@"currentTime": _labelCurrentTime, 125 | @"slider": _playerSlider, 126 | @"remainingTime": _labelRemainingTime}; 127 | 128 | NSArray *constraints1 = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[currentTime]-[slider]-[remainingTime]-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]; 129 | [self addConstraints:constraints1]; 130 | 131 | NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[slider]|" options:0 metrics:nil views:views]; 132 | [self addConstraints:constraints2]; 133 | 134 | [self addConstraint:[NSLayoutConstraint constraintWithItem:_playerSlider attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; 135 | } 136 | } 137 | 138 | - (void)prepareForInterfaceBuilder 139 | { 140 | self.duration = 60; 141 | self.currentTime = 17; 142 | [self updateRemainingTimeLabel]; 143 | } 144 | 145 | - (void)setShowRemainingTime:(BOOL)showRemainingTime 146 | { 147 | _showRemainingTime = showRemainingTime; 148 | 149 | [self updateRemainingTimeLabel]; 150 | } 151 | 152 | - (void)setDuration:(NSTimeInterval)duration 153 | { 154 | _duration = duration; 155 | _playerSlider.maximumValue = duration; 156 | 157 | [self updateRemainingTimeLabel]; 158 | } 159 | 160 | -(void)setCurrentTime:(NSTimeInterval)currentTime 161 | { 162 | [self setCurrentTime:currentTime animated:NO]; 163 | } 164 | 165 | - (void)setCurrentTime:(NSTimeInterval)currentTime animated:(BOOL)animated 166 | { 167 | _currentTime = currentTime; 168 | [_playerSlider setValue:currentTime animated:animated]; 169 | _labelCurrentTime.text = [NSString timeStringForTimeInterval:currentTime]; 170 | 171 | [self updateRemainingTimeLabel]; 172 | } 173 | 174 | #pragma mark Private methods 175 | 176 | - (void)updateRemainingTimeLabel 177 | { 178 | if (self.showRemainingTime) 179 | { 180 | _labelRemainingTime.text = [NSString timeStringForTimeInterval:(self.duration-self.currentTime)]; 181 | } 182 | else 183 | { 184 | _labelRemainingTime.text = [NSString timeStringForTimeInterval:self.duration]; 185 | } 186 | } 187 | 188 | - (void)toggleRemainingTimeDisplay:(UITapGestureRecognizer*)gesture 189 | { 190 | if (gesture.state == UIGestureRecognizerStateEnded) 191 | { 192 | self.showRemainingTime = !self.showRemainingTime; 193 | } 194 | } 195 | 196 | -(void)sliderStart 197 | { 198 | if ([self.delegate respondsToSelector:@selector(playbackDurationView:didStartScrubbingAtTime:)]) 199 | { 200 | [self.delegate playbackDurationView:self didStartScrubbingAtTime:_playerSlider.value]; 201 | } 202 | } 203 | 204 | -(void)sliderMoved 205 | { 206 | if ([self.delegate respondsToSelector:@selector(playbackDurationView:didScrubToTime:)]) 207 | { 208 | [self.delegate playbackDurationView:self didScrubToTime:_playerSlider.value]; 209 | } 210 | } 211 | 212 | -(void)sliderEnd 213 | { 214 | if ([self.delegate respondsToSelector:@selector(playbackDurationView:didEndScrubbingAtTime:)]) 215 | { 216 | [self.delegate playbackDurationView:self didEndScrubbingAtTime:_playerSlider.value]; 217 | } 218 | } 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /IQAudioRecorderController/NSString+IQTimeIntervalFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+IQTimeIntervalFormatter.h 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | 27 | @interface NSString (IQTimeIntervalFormatter) 28 | 29 | +(nonnull NSString*)timeStringForTimeInterval:(NSTimeInterval)timeInterval; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /IQAudioRecorderController/NSString+IQTimeIntervalFormatter.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+IQTimeIntervalFormatter.m 3 | // https://github.com/hackiftekhar/IQAudioRecorderController 4 | // Created by Iftekhar Qurashi 5 | // Copyright (c) 2015-16 Iftekhar Qurashi 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import "NSString+IQTimeIntervalFormatter.h" 26 | 27 | @implementation NSString (IQTimeIntervalFormatter) 28 | 29 | +(NSString*)timeStringForTimeInterval:(NSTimeInterval)timeInterval 30 | { 31 | NSInteger ti = (NSInteger)timeInterval; 32 | NSInteger seconds = ti % 60; 33 | NSInteger minutes = (ti / 60) % 60; 34 | NSInteger hours = (ti / 3600); 35 | 36 | if (hours > 0) 37 | { 38 | return [NSString stringWithFormat:@"%02li:%02li:%02li", (long)hours, (long)minutes, (long)seconds]; 39 | } 40 | else 41 | { 42 | return [NSString stringWithFormat:@"%02li:%02li", (long)minutes, (long)seconds]; 43 | } 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/.DS_Store -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/audio_record@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/microphone_access@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/scissor@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_playing@3x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording@2x.png -------------------------------------------------------------------------------- /IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/IQAudioRecorderController/Resources/IQAudioRecorderController.bundle/stop_recording@3x.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mohd Iftekhar Qurashi 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 | 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | project 'IQAudioRecorderController Demo.xcodeproj' 2 | 3 | platform :ios, '8.0' 4 | 5 | target 'IQAudioRecorderController Demo' do 6 | pod "IQAudioRecorderController", :path => "." 7 | end 8 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - IQAudioRecorderController (1.2.3): 3 | - SCSiriWaveformView 4 | - SCSiriWaveformView (1.1.1) 5 | 6 | DEPENDENCIES: 7 | - IQAudioRecorderController (from `.`) 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - SCSiriWaveformView 12 | 13 | EXTERNAL SOURCES: 14 | IQAudioRecorderController: 15 | :path: "." 16 | 17 | SPEC CHECKSUMS: 18 | IQAudioRecorderController: cb2dbf00bf26e84ac183fbf4077cfd2d1f29abec 19 | SCSiriWaveformView: 15b9dd6f94c7536e2032b34a35c6ff74d38c7411 20 | 21 | PODFILE CHECKSUM: 8f86a9bff719fe87000669f4d4dd77ed3b5cd532 22 | 23 | COCOAPODS: 1.5.3 24 | -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQAudioCropperViewController.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQAudioCropperViewController.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQAudioRecorderViewController.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQAudioRecorderViewController.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQCropSelectionBeginView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQCropSelectionBeginView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQCropSelectionEndView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQCropSelectionEndView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQCropSelectionView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQCropSelectionView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQMessageDisplayView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQMessageDisplayView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQPlaybackDurationView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQPlaybackDurationView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/IQ_FDWaveformView.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/FDWaveformView/IQ_FDWaveformView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/IQAudioRecorderController/NSString+IQTimeIntervalFormatter.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/NSString+IQTimeIntervalFormatter.h -------------------------------------------------------------------------------- /Pods/Headers/Private/SCSiriWaveformView/SCSiriWaveformView.h: -------------------------------------------------------------------------------- 1 | ../../../SCSiriWaveformView/SCSiriWaveformView/SCSiriWaveformView.h -------------------------------------------------------------------------------- /Pods/Headers/Public/IQAudioRecorderController/IQAudioCropperViewController.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQAudioCropperViewController.h -------------------------------------------------------------------------------- /Pods/Headers/Public/IQAudioRecorderController/IQAudioRecorderViewController.h: -------------------------------------------------------------------------------- 1 | ../../../../IQAudioRecorderController/IQAudioRecorderViewController.h -------------------------------------------------------------------------------- /Pods/Headers/Public/SCSiriWaveformView/SCSiriWaveformView.h: -------------------------------------------------------------------------------- 1 | ../../../SCSiriWaveformView/SCSiriWaveformView/SCSiriWaveformView.h -------------------------------------------------------------------------------- /Pods/Local Podspecs/IQAudioRecorderController.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IQAudioRecorderController", 3 | "version": "1.2.3", 4 | "source": { 5 | "git": "https://github.com/hackiftekhar/IQAudioRecorderController.git", 6 | "tag": "v1.2.3" 7 | }, 8 | "summary": "A drop-in universal library allows to record audio within the app with a nice User Interface.", 9 | "homepage": "https://github.com/hackiftekhar/IQAudioRecorderController", 10 | "license": "MIT", 11 | "authors": { 12 | "Iftekhar Qurashi": "hack.iftekhar@gmail.com" 13 | }, 14 | "platforms": { 15 | "ios": "8.0" 16 | }, 17 | "source_files": "IQAudioRecorderController/**/*.{h,m}", 18 | "public_header_files": [ 19 | "IQAudioRecorderController/IQAudioRecorderViewController.h", 20 | "IQAudioRecorderController/IQAudioCropperViewController.h", 21 | "IQAudioRecorderController/IQAudioRecorderConstants.h" 22 | ], 23 | "resources": "IQAudioRecorderController/Resources/*.*", 24 | "frameworks": [ 25 | "AVFoundation", 26 | "CoreAudio", 27 | "CoreGraphics", 28 | "CoreMotion", 29 | "Foundation", 30 | "UIKit" 31 | ], 32 | "dependencies": { 33 | "SCSiriWaveformView": [ 34 | 35 | ] 36 | }, 37 | "requires_arc": true 38 | } 39 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - IQAudioRecorderController (1.2.3): 3 | - SCSiriWaveformView 4 | - SCSiriWaveformView (1.1.1) 5 | 6 | DEPENDENCIES: 7 | - IQAudioRecorderController (from `.`) 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - SCSiriWaveformView 12 | 13 | EXTERNAL SOURCES: 14 | IQAudioRecorderController: 15 | :path: "." 16 | 17 | SPEC CHECKSUMS: 18 | IQAudioRecorderController: cb2dbf00bf26e84ac183fbf4077cfd2d1f29abec 19 | SCSiriWaveformView: 15b9dd6f94c7536e2032b34a35c6ff74d38c7411 20 | 21 | PODFILE CHECKSUM: 8f86a9bff719fe87000669f4d4dd77ed3b5cd532 22 | 23 | COCOAPODS: 1.5.3 24 | -------------------------------------------------------------------------------- /Pods/SCSiriWaveformView/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 | -------------------------------------------------------------------------------- /Pods/SCSiriWaveformView/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/uc?export=download&id=0ByLCkUO90ltoSVloLXRKSC1DbEk) 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 | ### License 17 | SCSiriWaveformView is released under the MIT License (MIT) (see the LICENSE file) 18 | 19 | ### Contact 20 | Any suggestions or improvements are more than welcome.
21 | Feel free to contact me at [stefan.ceriu@yahoo.com](mailto:stefan.ceriu@yahoo.com) or [@stefanceriu](https://twitter.com/stefanceriu). 22 | -------------------------------------------------------------------------------- /Pods/SCSiriWaveformView/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 | -------------------------------------------------------------------------------- /Pods/SCSiriWaveformView/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 | -------------------------------------------------------------------------------- /Pods/Target Support Files/IQAudioRecorderController/IQAudioRecorderController-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_IQAudioRecorderController : NSObject 3 | @end 4 | @implementation PodsDummy_IQAudioRecorderController 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/IQAudioRecorderController/IQAudioRecorderController-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/IQAudioRecorderController/IQAudioRecorderController.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/IQAudioRecorderController 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/IQAudioRecorderController" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IQAudioRecorderController" "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SCSiriWaveformView" 5 | OTHER_LDFLAGS = -framework "AVFoundation" -framework "CoreAudio" -framework "CoreGraphics" -framework "CoreMotion" -framework "Foundation" -framework "UIKit" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/.. 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## IQAudioRecorderController 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2015 Mohd Iftekhar Qurashi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | 29 | 30 | ## SCSiriWaveformView 31 | 32 | 33 | The MIT License (MIT) 34 | 35 | Copyright (c) [2013] [Stefan Ceriu] 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining a copy of 38 | this software and associated documentation files (the "Software"), to deal in 39 | the Software without restriction, including without limitation the rights to 40 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 41 | the Software, and to permit persons to whom the Software is furnished to do so, 42 | subject to the following conditions: 43 | 44 | The above copyright notice and this permission notice shall be included in all 45 | copies or substantial portions of the Software. 46 | 47 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 48 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 49 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 50 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 51 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 52 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 53 | 54 | 55 | 56 | Generated by CocoaPods - https://cocoapods.org 57 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2015 Mohd Iftekhar Qurashi 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | 40 | License 41 | MIT 42 | Title 43 | IQAudioRecorderController 44 | Type 45 | PSGroupSpecifier 46 | 47 | 48 | FooterText 49 | 50 | The MIT License (MIT) 51 | 52 | Copyright (c) [2013] [Stefan Ceriu] 53 | 54 | Permission is hereby granted, free of charge, to any person obtaining a copy of 55 | this software and associated documentation files (the "Software"), to deal in 56 | the Software without restriction, including without limitation the rights to 57 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 58 | the Software, and to permit persons to whom the Software is furnished to do so, 59 | subject to the following conditions: 60 | 61 | The above copyright notice and this permission notice shall be included in all 62 | copies or substantial portions of the Software. 63 | 64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 66 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 67 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 68 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 69 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 70 | 71 | 72 | 73 | License 74 | MIT License 75 | Title 76 | SCSiriWaveformView 77 | Type 78 | PSGroupSpecifier 79 | 80 | 81 | FooterText 82 | Generated by CocoaPods - https://cocoapods.org 83 | Title 84 | 85 | Type 86 | PSGroupSpecifier 87 | 88 | 89 | StringsTable 90 | Acknowledgements 91 | Title 92 | Acknowledgements 93 | 94 | 95 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_IQAudioRecorderController_Demo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_IQAudioRecorderController_Demo 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # frameworks to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 14 | 15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 17 | 18 | # Used as a return value for each invocation of `strip_invalid_archs` function. 19 | STRIP_BINARY_RETVAL=0 20 | 21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 24 | 25 | # Copies and strips a vendored framework 26 | install_framework() 27 | { 28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 29 | local source="${BUILT_PRODUCTS_DIR}/$1" 30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 32 | elif [ -r "$1" ]; then 33 | local source="$1" 34 | fi 35 | 36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 37 | 38 | if [ -L "${source}" ]; then 39 | echo "Symlinked..." 40 | source="$(readlink "${source}")" 41 | fi 42 | 43 | # Use filter instead of exclude so missing patterns don't throw errors. 44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 46 | 47 | local basename 48 | basename="$(basename -s .framework "$1")" 49 | binary="${destination}/${basename}.framework/${basename}" 50 | if ! [ -r "$binary" ]; then 51 | binary="${destination}/${basename}" 52 | fi 53 | 54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 56 | strip_invalid_archs "$binary" 57 | fi 58 | 59 | # Resign the code if required by the build settings to avoid unstable apps 60 | code_sign_if_enabled "${destination}/$(basename "$1")" 61 | 62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 64 | local swift_runtime_libs 65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 66 | for lib in $swift_runtime_libs; do 67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 69 | code_sign_if_enabled "${destination}/${lib}" 70 | done 71 | fi 72 | } 73 | 74 | # Copies and strips a vendored dSYM 75 | install_dsym() { 76 | local source="$1" 77 | if [ -r "$source" ]; then 78 | # Copy the dSYM into a the targets temp dir. 79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 81 | 82 | local basename 83 | basename="$(basename -s .framework.dSYM "$source")" 84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 85 | 86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 88 | strip_invalid_archs "$binary" 89 | fi 90 | 91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 92 | # Move the stripped file into its final destination. 93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 95 | else 96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 98 | fi 99 | fi 100 | } 101 | 102 | # Signs a framework with the provided identity 103 | code_sign_if_enabled() { 104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 105 | # Use the current code_sign_identitiy 106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 108 | 109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 110 | code_sign_cmd="$code_sign_cmd &" 111 | fi 112 | echo "$code_sign_cmd" 113 | eval "$code_sign_cmd" 114 | fi 115 | } 116 | 117 | # Strip invalid architectures 118 | strip_invalid_archs() { 119 | binary="$1" 120 | # Get architectures for current target binary 121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 122 | # Intersect them with the architectures we are building for 123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 124 | # If there are no archs supported by this binary then warn the user 125 | if [[ -z "$intersected_archs" ]]; then 126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 127 | STRIP_BINARY_RETVAL=0 128 | return 129 | fi 130 | stripped="" 131 | for arch in $binary_archs; do 132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 133 | # Strip non-valid architectures in-place 134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 135 | stripped="$stripped $arch" 136 | fi 137 | done 138 | if [[ "$stripped" ]]; then 139 | echo "Stripped $binary of architectures:$stripped" 140 | fi 141 | STRIP_BINARY_RETVAL=1 142 | } 143 | 144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 145 | wait 146 | fi 147 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | if [[ "$CONFIGURATION" == "Debug" ]]; then 95 | install_resource "${PODS_ROOT}/../IQAudioRecorderController/Resources/IQAudioRecorderController.bundle" 96 | fi 97 | if [[ "$CONFIGURATION" == "Release" ]]; then 98 | install_resource "${PODS_ROOT}/../IQAudioRecorderController/Resources/IQAudioRecorderController.bundle" 99 | fi 100 | 101 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 102 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 103 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 104 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 105 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | rm -f "$RESOURCES_TO_COPY" 108 | 109 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 110 | then 111 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 112 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 113 | while read line; do 114 | if [[ $line != "${PODS_ROOT}*" ]]; then 115 | XCASSET_FILES+=("$line") 116 | fi 117 | done <<<"$OTHER_XCASSETS" 118 | 119 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 120 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 121 | else 122 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 123 | fi 124 | fi 125 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IQAudioRecorderController" "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/IQAudioRecorderController" "${PODS_CONFIGURATION_BUILD_DIR}/SCSiriWaveformView" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/IQAudioRecorderController" -isystem "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"IQAudioRecorderController" -l"SCSiriWaveformView" -framework "AVFoundation" -framework "CoreAudio" -framework "CoreGraphics" -framework "CoreMotion" -framework "Foundation" -framework "QuartzCore" -framework "UIKit" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-IQAudioRecorderController Demo/Pods-IQAudioRecorderController Demo.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/IQAudioRecorderController" "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/IQAudioRecorderController" "${PODS_CONFIGURATION_BUILD_DIR}/SCSiriWaveformView" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/IQAudioRecorderController" -isystem "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"IQAudioRecorderController" -l"SCSiriWaveformView" -framework "AVFoundation" -framework "CoreAudio" -framework "CoreGraphics" -framework "CoreMotion" -framework "Foundation" -framework "QuartzCore" -framework "UIKit" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SCSiriWaveformView/SCSiriWaveformView-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SCSiriWaveformView : NSObject 3 | @end 4 | @implementation PodsDummy_SCSiriWaveformView 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SCSiriWaveformView/SCSiriWaveformView-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/SCSiriWaveformView/SCSiriWaveformView.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SCSiriWaveformView 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SCSiriWaveformView" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/SCSiriWaveformView" 4 | OTHER_LDFLAGS = -framework "AVFoundation" -framework "CoreGraphics" -framework "Foundation" -framework "QuartzCore" -framework "UIKit" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SCSiriWaveformView 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Icon 3 |

4 |

IQAudioRecorderController

5 | 6 | `IQAudioRecorderController` is a drop-in universal library allows to record and crop audio within the app with a nice User Interface. There are also optional callback delegate methods to return recorded file path. 7 | 8 | ![Idle](./Screenshot/Screenshot_Idle.jpeg) 9 | ![Recording](./Screenshot/Screenshot_Recording.jpg) 10 | ![Playing](./Screenshot/Screenshot_Playing.jpeg) 11 | ![No Access](./Screenshot/Screenshot_Cropping.jpg) 12 | 13 | ## Installation 14 | 15 | #### CocoaPods 16 | You can use [CocoaPods](http://cocoapods.org/) to install `IQAudioRecorderController` by adding it to your `Podfile`: 17 | 18 | ```ruby 19 | platform :ios, '8.0' 20 | use_frameworks! 21 | pod 'IQAudioRecorderController' 22 | ``` 23 | 24 | To get the full benefits import `IQAudioRecorderController` wherever you import UIKit 25 | 26 | ``` swift 27 | import UIKit 28 | import IQAudioRecorderController 29 | ``` 30 | 31 | #### Manually 32 | 1. Download and drop ```/IQAudioRecorderController```folder in your project. 33 | 2. Congratulations! 34 | 35 | ## Supported format 36 | Currently `IQAudioRecorderController` library only support **.m4a** file format. 37 | 38 | ## Customization 39 | There are optional properties to customize the appearance according to your app theme. 40 | 41 | ***barStyle: UIBarStyle:*** 42 | Library support light and dark style UI for user interface. If you would like to present light style UI then you need to set barStyle to UIBarStyleDefault, otherwise dark style UI is the default. 43 | 44 | ***normalTintColor: UIColor:*** 45 | This tintColor is used for showing wave tintColor while not recording, it is also used for top navigationBar and bottom toolbar tintColor. 46 | 47 | ***highlightedTintColor: UIColor:*** 48 | Highlighted tintColor is used when playing recorded audio file or when recording audio file. 49 | 50 | ## How to use 51 | 52 | There are two seprate classes to Record and Crop Audio files. 53 | 54 | To Record audio file, try something like this:- 55 | 56 | ```objc 57 | #import "IQAudioRecorderViewController.h" 58 | 59 | @interface ViewController () 60 | @end 61 | 62 | @implementation ViewController 63 | 64 | - (void)recordAction:(id)sender { 65 | IQAudioRecorderViewController *controller = [[IQAudioRecorderViewController alloc] init]; 66 | controller.delegate = self; 67 | controller.title = "Recorder"; 68 | controller.maximumRecordDuration = 10; 69 | controller.allowCropping = YES; 70 | // controller.barStyle = UIBarStyleDefault; 71 | // controller.normalTintColor = [UIColor magentaColor]; 72 | // controller.highlightedTintColor = [UIColor orangeColor]; 73 | [self presentBlurredAudioRecorderViewControllerAnimated:controller]; 74 | } 75 | 76 | -(void)audioRecorderController:(IQAudioRecorderViewController *)controller didFinishWithAudioAtPath:(NSString *)filePath { 77 | //Do your custom work with file at filePath. 78 | [controller dismissViewControllerAnimated:YES completion:nil]; 79 | } 80 | 81 | -(void)audioRecorderControllerDidCancel:(IQAudioRecorderViewController *)controller { 82 | //Notifying that user has clicked cancel. 83 | [controller dismissViewControllerAnimated:YES completion:nil]; 84 | } 85 | 86 | @end 87 | ``` 88 | 89 | To Crop audio file, try something like this:- 90 | 91 | ```objc 92 | #import "IQAudioCropperViewController.h" 93 | 94 | @interface ViewController () 95 | @end 96 | 97 | @implementation ViewController 98 | 99 | -(void)cropAction:(id)item { 100 | IQAudioCropperViewController *controller = [[IQAudioCropperViewController alloc] initWithFilePath:filePath]; 101 | controller.delegate = self; 102 | controller.title = "Edit"; 103 | // controller.barStyle = UIBarStyleDefault; 104 | // controller.normalTintColor = [UIColor magentaColor]; 105 | // controller.highlightedTintColor = [UIColor orangeColor]; 106 | [self presentBlurredAudioCropperViewControllerAnimated:controller]; 107 | } 108 | 109 | -(void)audioCropperController:(IQAudioCropperViewController *)controller didFinishWithAudioAtPath:(NSString *)filePath { 110 | //Do your custom work with file at filePath. 111 | [controller dismissViewControllerAnimated:YES completion:nil]; 112 | } 113 | 114 | -(void)audioCropperControllerDidCancel:(IQAudioCropperViewController *)controller { 115 | //Notifying that user has clicked cancel. 116 | [controller dismissViewControllerAnimated:YES completion:nil]; 117 | } 118 | 119 | @end 120 | ``` 121 | 122 | ## Attributions 123 | 124 | Thanks to [Stefan Ceriu](https://github.com/stefanceriu) for his brilliant [SCSiriWaveformView](https://github.com/stefanceriu/SCSiriWaveformView) library. 125 | 126 | Thanks to [William Entriken](https://github.com/fulldecent) for his [FDWaveformView](https://github.com/fulldecent/FDWaveformView) library. 127 | 128 | ## LICENSE 129 | 130 | Distributed under the MIT license. See ``LICENSE`` for more information. 131 | 132 | ## Contributions 133 | 134 | Any contribution is more than welcome! You can contribute through pull requests and issues on GitHub. 135 | 136 | ## Author 137 | 138 | If you wish to contact me, email at: hack.iftekhar@gmail.com 139 | -------------------------------------------------------------------------------- /Screenshot/Screenshot_Cropping.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/Screenshot_Cropping.jpg -------------------------------------------------------------------------------- /Screenshot/Screenshot_Idle.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/Screenshot_Idle.jpeg -------------------------------------------------------------------------------- /Screenshot/Screenshot_No_Access.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/Screenshot_No_Access.jpeg -------------------------------------------------------------------------------- /Screenshot/Screenshot_Playing.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/Screenshot_Playing.jpeg -------------------------------------------------------------------------------- /Screenshot/Screenshot_Recording.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/Screenshot_Recording.jpg -------------------------------------------------------------------------------- /Screenshot/iconScreenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackiftekhar/IQAudioRecorderController/4641f0118c13f8d7b74fb187fc055e62d1512167/Screenshot/iconScreenshot.png --------------------------------------------------------------------------------