├── .gitignore
├── LICENSE
├── README.md
├── SiriWave
├── SiriWave.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── SiriWave
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── Utility
│ ├── DateExtension.swift
│ ├── Lerp.swift
│ └── Timeout.swift
│ ├── ViewController.swift
│ └── Views
│ ├── SiriWaveLine.swift
│ └── SiriWaveView.swift
└── siri-wave-ios9+.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots/**/*.png
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 mapo80
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SiriWave
2 |
3 | The "Apple Siri" wave replicated in pure Swift.
4 |
5 | It was inspired by this library: https://github.com/kopiro/siriwave
6 |
7 | If you want to know what are the mathematical functions for its operation, you can read this post written by Flavio De Stefano:
8 | https://medium.freecodecamp.org/how-i-built-siriwavejs-library-maths-and-code-behind-6971497ae5c1
9 |
10 | ### iOS 9+ style
11 |
12 |
13 | ## Usage
14 |
15 | To use it add SiriWaveView.swift in you project.
16 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 890CBC0E2362263F002BEF06 /* SiriWaveLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890CBC0D2362263F002BEF06 /* SiriWaveLine.swift */; };
11 | C88D36D02232FB2F00594238 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36CF2232FB2F00594238 /* AppDelegate.swift */; };
12 | C88D36D22232FB2F00594238 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36D12232FB2F00594238 /* ViewController.swift */; };
13 | C88D36D52232FB2F00594238 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C88D36D32232FB2F00594238 /* Main.storyboard */; };
14 | C88D36D72232FB3000594238 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C88D36D62232FB3000594238 /* Assets.xcassets */; };
15 | C88D36DA2232FB3000594238 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C88D36D82232FB3000594238 /* LaunchScreen.storyboard */; };
16 | C88D36E32232FB9200594238 /* SiriWaveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36E22232FB9200594238 /* SiriWaveView.swift */; };
17 | C88D36F32233D61800594238 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36F22233D61800594238 /* DateExtension.swift */; };
18 | C88D36F52233D63800594238 /* Lerp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36F42233D63800594238 /* Lerp.swift */; };
19 | C88D36F72233D66000594238 /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88D36F62233D66000594238 /* Timeout.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 890CBC0D2362263F002BEF06 /* SiriWaveLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiriWaveLine.swift; sourceTree = ""; };
24 | C88D36CC2232FB2F00594238 /* SiriWave.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SiriWave.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | C88D36CF2232FB2F00594238 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
26 | C88D36D12232FB2F00594238 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | C88D36D42232FB2F00594238 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | C88D36D62232FB3000594238 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | C88D36D92232FB3000594238 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
30 | C88D36DB2232FB3000594238 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | C88D36E22232FB9200594238 /* SiriWaveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiriWaveView.swift; sourceTree = ""; };
32 | C88D36F22233D61800594238 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = ""; };
33 | C88D36F42233D63800594238 /* Lerp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lerp.swift; sourceTree = ""; };
34 | C88D36F62233D66000594238 /* Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timeout.swift; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | C88D36C92232FB2F00594238 /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | C88D36C32232FB2F00594238 = {
49 | isa = PBXGroup;
50 | children = (
51 | C88D36CE2232FB2F00594238 /* SiriWave */,
52 | C88D36CD2232FB2F00594238 /* Products */,
53 | );
54 | sourceTree = "";
55 | };
56 | C88D36CD2232FB2F00594238 /* Products */ = {
57 | isa = PBXGroup;
58 | children = (
59 | C88D36CC2232FB2F00594238 /* SiriWave.app */,
60 | );
61 | name = Products;
62 | sourceTree = "";
63 | };
64 | C88D36CE2232FB2F00594238 /* SiriWave */ = {
65 | isa = PBXGroup;
66 | children = (
67 | C88D36F12233D60600594238 /* Utility */,
68 | C88D36E12232FB6E00594238 /* Views */,
69 | C88D36CF2232FB2F00594238 /* AppDelegate.swift */,
70 | C88D36D12232FB2F00594238 /* ViewController.swift */,
71 | C88D36D32232FB2F00594238 /* Main.storyboard */,
72 | C88D36D62232FB3000594238 /* Assets.xcassets */,
73 | C88D36D82232FB3000594238 /* LaunchScreen.storyboard */,
74 | C88D36DB2232FB3000594238 /* Info.plist */,
75 | );
76 | path = SiriWave;
77 | sourceTree = "";
78 | };
79 | C88D36E12232FB6E00594238 /* Views */ = {
80 | isa = PBXGroup;
81 | children = (
82 | C88D36E22232FB9200594238 /* SiriWaveView.swift */,
83 | 890CBC0D2362263F002BEF06 /* SiriWaveLine.swift */,
84 | );
85 | path = Views;
86 | sourceTree = "";
87 | };
88 | C88D36F12233D60600594238 /* Utility */ = {
89 | isa = PBXGroup;
90 | children = (
91 | C88D36F22233D61800594238 /* DateExtension.swift */,
92 | C88D36F42233D63800594238 /* Lerp.swift */,
93 | C88D36F62233D66000594238 /* Timeout.swift */,
94 | );
95 | path = Utility;
96 | sourceTree = "";
97 | };
98 | /* End PBXGroup section */
99 |
100 | /* Begin PBXNativeTarget section */
101 | C88D36CB2232FB2F00594238 /* SiriWave */ = {
102 | isa = PBXNativeTarget;
103 | buildConfigurationList = C88D36DE2232FB3000594238 /* Build configuration list for PBXNativeTarget "SiriWave" */;
104 | buildPhases = (
105 | C88D36C82232FB2F00594238 /* Sources */,
106 | C88D36C92232FB2F00594238 /* Frameworks */,
107 | C88D36CA2232FB2F00594238 /* Resources */,
108 | );
109 | buildRules = (
110 | );
111 | dependencies = (
112 | );
113 | name = SiriWave;
114 | productName = SiriWave;
115 | productReference = C88D36CC2232FB2F00594238 /* SiriWave.app */;
116 | productType = "com.apple.product-type.application";
117 | };
118 | /* End PBXNativeTarget section */
119 |
120 | /* Begin PBXProject section */
121 | C88D36C42232FB2F00594238 /* Project object */ = {
122 | isa = PBXProject;
123 | attributes = {
124 | LastSwiftUpdateCheck = 1010;
125 | LastUpgradeCheck = 1010;
126 | TargetAttributes = {
127 | C88D36CB2232FB2F00594238 = {
128 | CreatedOnToolsVersion = 10.1;
129 | };
130 | };
131 | };
132 | buildConfigurationList = C88D36C72232FB2F00594238 /* Build configuration list for PBXProject "SiriWave" */;
133 | compatibilityVersion = "Xcode 9.3";
134 | developmentRegion = en;
135 | hasScannedForEncodings = 0;
136 | knownRegions = (
137 | en,
138 | Base,
139 | );
140 | mainGroup = C88D36C32232FB2F00594238;
141 | productRefGroup = C88D36CD2232FB2F00594238 /* Products */;
142 | projectDirPath = "";
143 | projectRoot = "";
144 | targets = (
145 | C88D36CB2232FB2F00594238 /* SiriWave */,
146 | );
147 | };
148 | /* End PBXProject section */
149 |
150 | /* Begin PBXResourcesBuildPhase section */
151 | C88D36CA2232FB2F00594238 /* Resources */ = {
152 | isa = PBXResourcesBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | C88D36DA2232FB3000594238 /* LaunchScreen.storyboard in Resources */,
156 | C88D36D72232FB3000594238 /* Assets.xcassets in Resources */,
157 | C88D36D52232FB2F00594238 /* Main.storyboard in Resources */,
158 | );
159 | runOnlyForDeploymentPostprocessing = 0;
160 | };
161 | /* End PBXResourcesBuildPhase section */
162 |
163 | /* Begin PBXSourcesBuildPhase section */
164 | C88D36C82232FB2F00594238 /* Sources */ = {
165 | isa = PBXSourcesBuildPhase;
166 | buildActionMask = 2147483647;
167 | files = (
168 | C88D36D22232FB2F00594238 /* ViewController.swift in Sources */,
169 | C88D36F32233D61800594238 /* DateExtension.swift in Sources */,
170 | C88D36D02232FB2F00594238 /* AppDelegate.swift in Sources */,
171 | C88D36E32232FB9200594238 /* SiriWaveView.swift in Sources */,
172 | C88D36F52233D63800594238 /* Lerp.swift in Sources */,
173 | 890CBC0E2362263F002BEF06 /* SiriWaveLine.swift in Sources */,
174 | C88D36F72233D66000594238 /* Timeout.swift in Sources */,
175 | );
176 | runOnlyForDeploymentPostprocessing = 0;
177 | };
178 | /* End PBXSourcesBuildPhase section */
179 |
180 | /* Begin PBXVariantGroup section */
181 | C88D36D32232FB2F00594238 /* Main.storyboard */ = {
182 | isa = PBXVariantGroup;
183 | children = (
184 | C88D36D42232FB2F00594238 /* Base */,
185 | );
186 | name = Main.storyboard;
187 | sourceTree = "";
188 | };
189 | C88D36D82232FB3000594238 /* LaunchScreen.storyboard */ = {
190 | isa = PBXVariantGroup;
191 | children = (
192 | C88D36D92232FB3000594238 /* Base */,
193 | );
194 | name = LaunchScreen.storyboard;
195 | sourceTree = "";
196 | };
197 | /* End PBXVariantGroup section */
198 |
199 | /* Begin XCBuildConfiguration section */
200 | C88D36DC2232FB3000594238 /* Debug */ = {
201 | isa = XCBuildConfiguration;
202 | buildSettings = {
203 | ALWAYS_SEARCH_USER_PATHS = NO;
204 | CLANG_ANALYZER_NONNULL = YES;
205 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
206 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
207 | CLANG_CXX_LIBRARY = "libc++";
208 | CLANG_ENABLE_MODULES = YES;
209 | CLANG_ENABLE_OBJC_ARC = YES;
210 | CLANG_ENABLE_OBJC_WEAK = YES;
211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
212 | CLANG_WARN_BOOL_CONVERSION = YES;
213 | CLANG_WARN_COMMA = YES;
214 | CLANG_WARN_CONSTANT_CONVERSION = YES;
215 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
217 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
218 | CLANG_WARN_EMPTY_BODY = YES;
219 | CLANG_WARN_ENUM_CONVERSION = YES;
220 | CLANG_WARN_INFINITE_RECURSION = YES;
221 | CLANG_WARN_INT_CONVERSION = YES;
222 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
223 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
224 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
225 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
226 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
227 | CLANG_WARN_STRICT_PROTOTYPES = YES;
228 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
229 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
230 | CLANG_WARN_UNREACHABLE_CODE = YES;
231 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
232 | CODE_SIGN_IDENTITY = "iPhone Developer";
233 | COPY_PHASE_STRIP = NO;
234 | DEBUG_INFORMATION_FORMAT = dwarf;
235 | ENABLE_STRICT_OBJC_MSGSEND = YES;
236 | ENABLE_TESTABILITY = YES;
237 | GCC_C_LANGUAGE_STANDARD = gnu11;
238 | GCC_DYNAMIC_NO_PIC = NO;
239 | GCC_NO_COMMON_BLOCKS = YES;
240 | GCC_OPTIMIZATION_LEVEL = 0;
241 | GCC_PREPROCESSOR_DEFINITIONS = (
242 | "DEBUG=1",
243 | "$(inherited)",
244 | );
245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
247 | GCC_WARN_UNDECLARED_SELECTOR = YES;
248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
249 | GCC_WARN_UNUSED_FUNCTION = YES;
250 | GCC_WARN_UNUSED_VARIABLE = YES;
251 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
252 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
253 | MTL_FAST_MATH = YES;
254 | ONLY_ACTIVE_ARCH = YES;
255 | SDKROOT = iphoneos;
256 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
257 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
258 | SWIFT_VERSION = 5.0;
259 | };
260 | name = Debug;
261 | };
262 | C88D36DD2232FB3000594238 /* Release */ = {
263 | isa = XCBuildConfiguration;
264 | buildSettings = {
265 | ALWAYS_SEARCH_USER_PATHS = NO;
266 | CLANG_ANALYZER_NONNULL = YES;
267 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
269 | CLANG_CXX_LIBRARY = "libc++";
270 | CLANG_ENABLE_MODULES = YES;
271 | CLANG_ENABLE_OBJC_ARC = YES;
272 | CLANG_ENABLE_OBJC_WEAK = YES;
273 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
274 | CLANG_WARN_BOOL_CONVERSION = YES;
275 | CLANG_WARN_COMMA = YES;
276 | CLANG_WARN_CONSTANT_CONVERSION = YES;
277 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
279 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
280 | CLANG_WARN_EMPTY_BODY = YES;
281 | CLANG_WARN_ENUM_CONVERSION = YES;
282 | CLANG_WARN_INFINITE_RECURSION = YES;
283 | CLANG_WARN_INT_CONVERSION = YES;
284 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
286 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
289 | CLANG_WARN_STRICT_PROTOTYPES = YES;
290 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
291 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
292 | CLANG_WARN_UNREACHABLE_CODE = YES;
293 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
294 | CODE_SIGN_IDENTITY = "iPhone Developer";
295 | COPY_PHASE_STRIP = NO;
296 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
297 | ENABLE_NS_ASSERTIONS = NO;
298 | ENABLE_STRICT_OBJC_MSGSEND = YES;
299 | GCC_C_LANGUAGE_STANDARD = gnu11;
300 | GCC_NO_COMMON_BLOCKS = YES;
301 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
302 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
303 | GCC_WARN_UNDECLARED_SELECTOR = YES;
304 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
305 | GCC_WARN_UNUSED_FUNCTION = YES;
306 | GCC_WARN_UNUSED_VARIABLE = YES;
307 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
308 | MTL_ENABLE_DEBUG_INFO = NO;
309 | MTL_FAST_MATH = YES;
310 | SDKROOT = iphoneos;
311 | SWIFT_COMPILATION_MODE = wholemodule;
312 | SWIFT_OPTIMIZATION_LEVEL = "-O";
313 | SWIFT_VERSION = 5.0;
314 | VALIDATE_PRODUCT = YES;
315 | };
316 | name = Release;
317 | };
318 | C88D36DF2232FB3000594238 /* Debug */ = {
319 | isa = XCBuildConfiguration;
320 | buildSettings = {
321 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
322 | CODE_SIGN_STYLE = Automatic;
323 | DEVELOPMENT_TEAM = 94Q9JHN685;
324 | INFOPLIST_FILE = SiriWave/Info.plist;
325 | LD_RUNPATH_SEARCH_PATHS = (
326 | "$(inherited)",
327 | "@executable_path/Frameworks",
328 | );
329 | PRODUCT_BUNDLE_IDENTIFIER = com.stoltz.SiriWave;
330 | PRODUCT_NAME = "$(TARGET_NAME)";
331 | SWIFT_VERSION = 5.0;
332 | TARGETED_DEVICE_FAMILY = "1,2";
333 | };
334 | name = Debug;
335 | };
336 | C88D36E02232FB3000594238 /* Release */ = {
337 | isa = XCBuildConfiguration;
338 | buildSettings = {
339 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
340 | CODE_SIGN_STYLE = Automatic;
341 | DEVELOPMENT_TEAM = 94Q9JHN685;
342 | INFOPLIST_FILE = SiriWave/Info.plist;
343 | LD_RUNPATH_SEARCH_PATHS = (
344 | "$(inherited)",
345 | "@executable_path/Frameworks",
346 | );
347 | PRODUCT_BUNDLE_IDENTIFIER = com.stoltz.SiriWave;
348 | PRODUCT_NAME = "$(TARGET_NAME)";
349 | SWIFT_VERSION = 5.0;
350 | TARGETED_DEVICE_FAMILY = "1,2";
351 | };
352 | name = Release;
353 | };
354 | /* End XCBuildConfiguration section */
355 |
356 | /* Begin XCConfigurationList section */
357 | C88D36C72232FB2F00594238 /* Build configuration list for PBXProject "SiriWave" */ = {
358 | isa = XCConfigurationList;
359 | buildConfigurations = (
360 | C88D36DC2232FB3000594238 /* Debug */,
361 | C88D36DD2232FB3000594238 /* Release */,
362 | );
363 | defaultConfigurationIsVisible = 0;
364 | defaultConfigurationName = Release;
365 | };
366 | C88D36DE2232FB3000594238 /* Build configuration list for PBXNativeTarget "SiriWave" */ = {
367 | isa = XCConfigurationList;
368 | buildConfigurations = (
369 | C88D36DF2232FB3000594238 /* Debug */,
370 | C88D36E02232FB3000594238 /* Release */,
371 | );
372 | defaultConfigurationIsVisible = 0;
373 | defaultConfigurationName = Release;
374 | };
375 | /* End XCConfigurationList section */
376 | };
377 | rootObject = C88D36C42232FB2F00594238 /* Project object */;
378 | }
379 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 08/03/2019.
6 | //
7 |
8 | import UIKit
9 |
10 | @UIApplicationMain
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func application(_ application: UIApplication,
17 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Assets.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 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | NSMicrophoneUsageDescription
45 | Need microphone access to test Siri Wave
46 |
47 |
48 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Utility/DateExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateExtension.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 09/03/2019.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Date {
11 | var millisecondsSince1970: Int {
12 | return Int((self.timeIntervalSince1970 * 1000.0).rounded())
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Utility/Lerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Lerp.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 09/03/2019.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | public class Lerp {
12 | public static func lerp(_ v0: CGFloat, _ v1: CGFloat, _ t: CGFloat) -> CGFloat {
13 | return v0 * (1 - t) + v1 * t
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Utility/Timeout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Timeout.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 09/03/2019.
6 | //
7 |
8 | import Foundation
9 |
10 | public class Timeout {
11 |
12 | public typealias ComplectionBlock = () -> Void
13 |
14 | public static func setInterval(_ interval: TimeInterval,
15 | block: @escaping ComplectionBlock) -> Timer {
16 | return Timer.scheduledTimer(timeInterval: interval,
17 | target: BlockOperation(block: block),
18 | selector: #selector(Operation.main),
19 | userInfo: nil, repeats: true)
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 08/03/2019.
6 | //
7 |
8 | import UIKit
9 | import AVKit
10 |
11 | final class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var siriWave: SiriWaveView!
14 |
15 | private var recorder:AVAudioRecorder!
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | //setupRecorder()
21 | testWithoutMic()
22 | }
23 |
24 | private func testWithoutMic() {
25 | var ampl: CGFloat = 1
26 | let speed: CGFloat = 0.1
27 |
28 | func modulate() {
29 | ampl = Lerp.lerp(ampl, 1.5, speed)
30 | self.siriWave.update(ampl * 5)
31 | }
32 |
33 | _ = Timeout.setInterval(TimeInterval(speed)) {
34 | DispatchQueue.main.async {
35 | modulate()
36 | }
37 | }
38 | }
39 |
40 | /// Recorder Setup Begin
41 | @objc func setupRecorder() {
42 | if(checkMicPermission()) {
43 | startRecording()
44 | } else {
45 | print("permission denied")
46 | }
47 | }
48 |
49 | @objc func updateMeters() {
50 | var normalizedValue: Float
51 | recorder.updateMeters()
52 | normalizedValue = normalizedPowerLevelFromDecibels(decibels: recorder.averagePower(forChannel: 0))
53 | self.siriWave.update(CGFloat(normalizedValue) * 10)
54 | }
55 |
56 | private func startRecording() {
57 | let recordingSession = AVAudioSession.sharedInstance()
58 | let recorderSettings = [AVSampleRateKey: NSNumber(value: 44100.0),
59 | AVFormatIDKey: NSNumber(value: kAudioFormatAppleLossless),
60 | AVNumberOfChannelsKey: NSNumber(value: 2),
61 | AVEncoderAudioQualityKey: NSNumber(value: Int8(AVAudioQuality.min.rawValue))]
62 |
63 | let url: URL = URL(fileURLWithPath:"/dev/null")
64 | do {
65 |
66 | let displayLink: CADisplayLink = CADisplayLink(target: self,
67 | selector: #selector(ViewController.updateMeters))
68 | displayLink.add(to: RunLoop.current,
69 | forMode: RunLoop.Mode.common)
70 |
71 | try recordingSession.setCategory(.playAndRecord,
72 | mode: .default)
73 | try recordingSession.setActive(true)
74 | self.recorder = try AVAudioRecorder.init(url: url,
75 | settings: recorderSettings as [String : Any])
76 | self.recorder.prepareToRecord()
77 | self.recorder.isMeteringEnabled = true;
78 | self.recorder.record()
79 | print("recorder enabled")
80 | } catch {
81 | self.showErrorPopUp(errorMessage: error.localizedDescription)
82 | print("recorder init failed")
83 | }
84 | }
85 |
86 | private func checkMicPermission() -> Bool {
87 | var permissionCheck: Bool = false
88 |
89 | switch AVAudioSession.sharedInstance().recordPermission {
90 | case AVAudioSession.RecordPermission.granted:
91 | permissionCheck = true
92 | case AVAudioSession.RecordPermission.denied:
93 | permissionCheck = false
94 | case AVAudioSession.RecordPermission.undetermined:
95 | AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
96 | if granted {
97 | permissionCheck = true
98 | } else {
99 | permissionCheck = false
100 | }
101 | })
102 | default:
103 | break
104 | }
105 |
106 | return permissionCheck
107 | }
108 |
109 | private func normalizedPowerLevelFromDecibels(decibels: Float) -> Float {
110 | let minDecibels: Float = -60.0
111 | if (decibels < minDecibels || decibels.isZero) {
112 | return .zero
113 | }
114 |
115 | let powDecibels = pow(10.0, 0.05 * decibels)
116 | let powMinDecibels = pow(10.0, 0.05 * minDecibels)
117 | return pow((powDecibels - powMinDecibels) * (1.0 / (1.0 - powMinDecibels)), 1.0 / 2.0)
118 |
119 | }
120 |
121 | private func showErrorPopUp(errorMessage: String) {
122 | let alertController = UIAlertController(title: "Error",
123 | message: errorMessage,
124 | preferredStyle: .alert)
125 | let okAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
126 | alertController.addAction(okAction)
127 | present(alertController, animated: true, completion: nil)
128 | }
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Views/SiriWaveLine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SiriWaveLine.swift
3 | // SiriWave
4 | //
5 | // Created by Alexander Shoshiashvili on 24.10.2019.
6 | //
7 |
8 | import UIKit
9 |
10 | public class SiriWaveLine {
11 |
12 | let GRAPH_X: CGFloat = 25
13 | let AMPLITUDE_FACTOR: CGFloat = 0.8
14 | let SPEED_FACTOR: CGFloat = 1
15 | let DEAD_PX: CGFloat = 2
16 | let ATT_FACTOR: CGFloat = 4
17 | let DESPAWN_FACTOR: CGFloat = 0.02
18 | let NOOFCURVES_RANGES: [CGFloat] = [5, 5]
19 | let AMPLITUDE_RANGES: [CGFloat] = [0.3, 1]
20 | let OFFSET_RANGES: [CGFloat] = [-3, 3]
21 | let WIDTH_RANGES: [CGFloat] = [1, 3]
22 | let SPEED_RANGES: [CGFloat] = [0.5, 1]
23 | let DESPAWN_TIMEOUT_RANGES: [CGFloat] = [500, 2000]
24 |
25 | var spawnAt: Int = Date().millisecondsSince1970
26 | var noOfCurves: Int!
27 | var phases: [CGFloat] = []
28 | var offsets: [CGFloat] = []
29 | var speeds: [CGFloat] = []
30 | var finalAmplitudes: [CGFloat] = []
31 | var widths: [CGFloat] = []
32 | var amplitudes: [CGFloat] = []
33 | var despawnTimeouts: [CGFloat] = []
34 | var verses: [CGFloat] = []
35 | var prevMaxY: CGFloat = 0
36 |
37 | public private (set) var amplitude: CGFloat
38 | public private (set) var speed: CGFloat
39 | public private (set) var pixelDepth: CGFloat
40 | public private (set) var heightMax: CGFloat
41 | public private (set) var width: CGFloat
42 | public private (set) var color: UIColor
43 |
44 | public init(amplitude: CGFloat,
45 | speed: CGFloat,
46 | pixelDepth: CGFloat,
47 | width: CGFloat,
48 | heightMax: CGFloat,
49 | color: UIColor) {
50 |
51 | self.amplitude = amplitude
52 | self.speed = speed
53 | self.pixelDepth = pixelDepth
54 | self.width = width
55 | self.heightMax = heightMax
56 | self.color = color
57 |
58 | commonInit()
59 | }
60 |
61 | private func commonInit() {
62 | self.spawnAt = Date().millisecondsSince1970
63 | self.noOfCurves = Int(floor(getRandomRange(NOOFCURVES_RANGES)))
64 |
65 | self.phases = Array(repeating: 0.0, count: noOfCurves)
66 | self.offsets = Array(repeating: 0.0, count: noOfCurves)
67 | self.speeds = Array(repeating: 0.0, count: noOfCurves)
68 | self.finalAmplitudes = Array(repeating: 0.0, count: noOfCurves)
69 | self.widths = Array(repeating: 0.0, count: noOfCurves)
70 | self.amplitudes = Array(repeating: 0.0, count: noOfCurves)
71 | self.despawnTimeouts = Array(repeating: 0.0, count: noOfCurves)
72 | self.verses = Array(repeating: 0.0, count: noOfCurves)
73 |
74 | for ci in 0.. maxY) {
132 | respawn()
133 | }
134 |
135 | prevMaxY = maxY
136 | }
137 |
138 | private func respawn() {
139 | commonInit()
140 | }
141 | private func respawnSingle(_ ci: Int) {
142 | self.phases[ci] = 0
143 | self.amplitudes[ci] = 0
144 |
145 | self.despawnTimeouts[ci] = getRandomRange(DESPAWN_TIMEOUT_RANGES)
146 | self.offsets[ci] = getRandomRange(OFFSET_RANGES)
147 | self.speeds[ci] = getRandomRange(SPEED_RANGES)
148 | self.finalAmplitudes[ci] = getRandomRange(AMPLITUDE_RANGES)
149 | self.widths[ci] = getRandomRange(WIDTH_RANGES)
150 | self.verses[ci] = getRandomRange([-1, 1])
151 | }
152 | private func yRelativePos(_ i: CGFloat) -> CGFloat {
153 | var y: CGFloat = 0
154 |
155 | for ci in 0.. CGFloat {
175 | return AMPLITUDE_FACTOR *
176 | heightMax *
177 | amplitude *
178 | yRelativePos(i) *
179 | globalAttFn(i / GRAPH_X * 2)
180 | }
181 | private func xpos(_ i: CGFloat) -> CGFloat {
182 | return width * ((i + GRAPH_X) / (GRAPH_X * 2))
183 | }
184 |
185 | private func getRandomRange(_ e: [CGFloat]) -> CGFloat {
186 | return e[0] + (CGFloat.random(in: 0 ..< 1) * (e[1] - e[0]))
187 | }
188 | private func globalAttFn(_ x: CGFloat) -> CGFloat {
189 | return pow((ATT_FACTOR) / (ATT_FACTOR + pow(x, 2)),
190 | ATT_FACTOR)
191 | }
192 | private func sinus(_ x: CGFloat, _ phase: CGFloat) -> CGFloat {
193 | return sin(x - phase)
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/SiriWave/SiriWave/Views/SiriWaveView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SiriWaveView.swift
3 | // SiriWave
4 | //
5 | // Created by politom on 08/03/2019.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIColor {
11 | convenience init(red: Int, green: Int, blue: Int) {
12 | assert(red >= 0 && red <= 255, "Invalid red component")
13 | assert(green >= 0 && green <= 255, "Invalid green component")
14 | assert(blue >= 0 && blue <= 255, "Invalid blue component")
15 |
16 | self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
17 | }
18 |
19 | convenience init(rgb: Int) {
20 | self.init(
21 | red: (rgb >> 16) & 0xFF,
22 | green: (rgb >> 8) & 0xFF,
23 | blue: rgb & 0xFF
24 | )
25 | }
26 | }
27 |
28 | public class SiriWaveView: UIView {
29 |
30 | public private (set) var pixelDepth: CGFloat = 0.4
31 | public private (set) var amplitude: CGFloat = 1
32 |
33 | @IBInspectable
34 | public var idleAmplitude: CGFloat = 0.01
35 | @IBInspectable
36 | public var speed: CGFloat = 0.4
37 |
38 | public var colors: [UIColor] = [UIColor(rgb: 0xF66767),
39 | UIColor(rgb: 0xF9D5BB),
40 | UIColor(rgb: 0xD35656)]
41 |
42 | private var lines: [SiriWaveLine] = []
43 |
44 | private var heightMax: CGFloat {
45 | return self.frame.height
46 | }
47 | private var width: CGFloat {
48 | return self.frame.width
49 | }
50 |
51 | public override init(frame: CGRect) {
52 | super.init(frame: frame)
53 | commonInit()
54 | }
55 |
56 | public required init?(coder aDecoder: NSCoder) {
57 | super.init(coder: aDecoder)
58 | commonInit()
59 | }
60 |
61 | public func update(_ level: CGFloat) {
62 |
63 | self.amplitude = fmax(level,
64 | idleAmplitude)
65 |
66 | self.setNeedsDisplay()
67 |
68 | }
69 |
70 | override public func draw(_ rect: CGRect) {
71 |
72 | if let ctx: CGContext = UIGraphicsGetCurrentContext() {
73 | ctx.setAlpha(0.7)
74 | ctx.setBlendMode(.lighten)
75 |
76 | drawSupportLine(ctx)
77 |
78 | for line in lines {
79 | line.drawLine(ctx,
80 | amplitude,
81 | speed)
82 | }
83 | }
84 | }
85 |
86 | private func commonInit() {
87 |
88 | for color in colors {
89 |
90 | lines.append(SiriWaveLine(amplitude: amplitude,
91 | speed: speed,
92 | pixelDepth: pixelDepth,
93 | width: width,
94 | heightMax: heightMax,
95 | color: color))
96 | }
97 |
98 | }
99 |
100 | private func drawSupportLine(_ ctx: CGContext) {
101 |
102 | let colors = [UIColor.clear.cgColor,
103 | UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor,
104 | UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor,
105 | UIColor.clear.cgColor]
106 |
107 | let colorSpace = CGColorSpaceCreateDeviceRGB()
108 | let colorLocations: [CGFloat] = [0.0, 0.1, 1.0, 0.8, 1]
109 | let gradient = CGGradient(colorsSpace: colorSpace,
110 | colors: colors as CFArray,
111 | locations: colorLocations)!
112 |
113 | let startPoint = CGPoint(x: 0, y: (heightMax/2)-0.5)
114 | let endPoint = CGPoint(x: 0, y: (heightMax/2)+0.5)
115 |
116 | ctx.drawLinearGradient(gradient,
117 | start: startPoint,
118 | end: endPoint,
119 | options: [])
120 | }
121 | }
122 |
123 |
124 |
--------------------------------------------------------------------------------
/siri-wave-ios9+.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapo80/SiriWave/de5d0327ae95fdf29fcd1f51a57468b1d8d484d8/siri-wave-ios9+.gif
--------------------------------------------------------------------------------