├── .gitignore ├── AVAEGamingExample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── dev.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── dev.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── iOS.xcscheme │ ├── macOS.xcscheme │ ├── tvOS.xcscheme │ └── xcschememanagement.plist ├── AVAEGamingExample ├── AudioEngine.h ├── AudioEngine.m ├── AudioEngine.swift ├── GameView.h ├── GameView.m ├── GameView.swift ├── GameViewController.h ├── GameViewController.m ├── GameViewController.swift ├── Images.xcassets │ ├── Contents.json │ └── texture.imageset │ │ ├── Contents.json │ │ └── texture.png ├── assets.scnassets │ ├── cube.scn │ ├── envmap.jpg │ ├── texture.jpg │ └── wall2.png ├── bounce.caf └── launchSound.caf ├── LICENSE.txt ├── README.md ├── README2.md ├── iOS ├── AppDelegate.h ├── AppDelegate.m ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── iOSMain.storyboard ├── Info.plist └── main.m ├── macOS ├── AppDelegate.h ├── AppDelegate.m ├── AppDelegate.swift ├── Info.plist ├── macOSMain.storyboard └── main.m └── tvOS ├── AppDelegate.h ├── AppDelegate.m ├── AppDelegate.swift ├── Base.lproj └── tvOSMain.storyboard ├── Info.plist └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B1A3C5691C179A07009C9FB6 /* macOSMain.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1A3C5641C179A07009C9FB6 /* macOSMain.storyboard */; }; 11 | B1A3C5951C179ACD009C9FB6 /* iOSMain.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1A3C57F1C179A65009C9FB6 /* iOSMain.storyboard */; }; 12 | B1A3C5961C179AD1009C9FB6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1A3C57D1C179A65009C9FB6 /* LaunchScreen.storyboard */; }; 13 | B1A3C59D1C179AE7009C9FB6 /* tvOSMain.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1A3C58A1C179A89009C9FB6 /* tvOSMain.storyboard */; }; 14 | B1D82D0E1BC2FA4700F4B330 /* bounce.caf in Resources */ = {isa = PBXBuildFile; fileRef = 3060564D192841990022B976 /* bounce.caf */; }; 15 | B1D82D0F1BC2FA4700F4B330 /* launchSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 30AD31B0192EC3120032BC30 /* launchSound.caf */; }; 16 | B1D82D151BC3004900F4B330 /* assets.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 94CA7B911924A91D0005BA4B /* assets.scnassets */; }; 17 | B1D82D5F1BC31C4000F4B330 /* bounce.caf in Resources */ = {isa = PBXBuildFile; fileRef = 3060564D192841990022B976 /* bounce.caf */; }; 18 | B1D82D601BC31C4000F4B330 /* launchSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 30AD31B0192EC3120032BC30 /* launchSound.caf */; }; 19 | B1D82D611BC31C4000F4B330 /* assets.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 94CA7B911924A91D0005BA4B /* assets.scnassets */; }; 20 | B1D82D681BC31C7100F4B330 /* bounce.caf in Resources */ = {isa = PBXBuildFile; fileRef = 3060564D192841990022B976 /* bounce.caf */; }; 21 | B1D82D691BC31C7100F4B330 /* launchSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 30AD31B0192EC3120032BC30 /* launchSound.caf */; }; 22 | B1D82D6A1BC31C7100F4B330 /* assets.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 94CA7B911924A91D0005BA4B /* assets.scnassets */; }; 23 | D75726941DFFD38F00F0E3D6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726931DFFD38F00F0E3D6 /* AppDelegate.swift */; }; 24 | D75726981DFFD3A000F0E3D6 /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726951DFFD3A000F0E3D6 /* AudioEngine.swift */; }; 25 | D75726991DFFD3A000F0E3D6 /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726961DFFD3A000F0E3D6 /* GameView.swift */; }; 26 | D757269A1DFFD3A000F0E3D6 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726971DFFD3A000F0E3D6 /* GameViewController.swift */; }; 27 | D757269B1DFFD41000F0E3D6 /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726951DFFD3A000F0E3D6 /* AudioEngine.swift */; }; 28 | D757269C1DFFD41100F0E3D6 /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726951DFFD3A000F0E3D6 /* AudioEngine.swift */; }; 29 | D757269D1DFFD5DD00F0E3D6 /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726961DFFD3A000F0E3D6 /* GameView.swift */; }; 30 | D757269E1DFFD5DE00F0E3D6 /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726961DFFD3A000F0E3D6 /* GameView.swift */; }; 31 | D757269F1DFFD5EB00F0E3D6 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726971DFFD3A000F0E3D6 /* GameViewController.swift */; }; 32 | D75726A01DFFD5ED00F0E3D6 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726971DFFD3A000F0E3D6 /* GameViewController.swift */; }; 33 | D75726A71DFFEEBE00F0E3D6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726A51DFFEE5500F0E3D6 /* AppDelegate.swift */; }; 34 | D75726AA1DFFF06000F0E3D6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75726A81DFFF00C00F0E3D6 /* AppDelegate.swift */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 3010A12519283C300006EB2D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = ../../../../../System/Library/Frameworks/AVFoundation.framework; sourceTree = ""; }; 39 | 3060564D192841990022B976 /* bounce.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = bounce.caf; sourceTree = ""; }; 40 | 30AD31B0192EC3120032BC30 /* launchSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = launchSound.caf; sourceTree = ""; }; 41 | 94CA7B761924A8C30005BA4B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 42 | 94CA7B8F1924A8D30005BA4B /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = /System/Library/Frameworks/SceneKit.framework; sourceTree = ""; }; 43 | 94CA7B911924A91D0005BA4B /* assets.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = assets.scnassets; sourceTree = ""; }; 44 | B1321A201DC9511F009C8FD1 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 45 | B1A3C5641C179A07009C9FB6 /* macOSMain.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = macOSMain.storyboard; sourceTree = ""; }; 46 | B1A3C5661C179A07009C9FB6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | B1A3C57C1C179A65009C9FB6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = iOS/Info.plist; sourceTree = SOURCE_ROOT; }; 48 | B1A3C57E1C179A65009C9FB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = iOS/Base.lproj/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; }; 49 | B1A3C5801C179A65009C9FB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = iOS/Base.lproj/iOSMain.storyboard; sourceTree = SOURCE_ROOT; }; 50 | B1A3C58B1C179A89009C9FB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = tvOS/Base.lproj/tvOSMain.storyboard; sourceTree = SOURCE_ROOT; }; 51 | B1A3C58C1C179A89009C9FB6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = tvOS/Info.plist; sourceTree = SOURCE_ROOT; }; 52 | B1D82CF71BC2F8CE00F4B330 /* AVAEGamingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AVAEGamingExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | B1D82D1A1BC3075C00F4B330 /* AVAEGamingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AVAEGamingExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | B1D82D491BC30A3800F4B330 /* AVAEGamingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AVAEGamingExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | D75726931DFFD38F00F0E3D6 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 56 | D75726951DFFD3A000F0E3D6 /* AudioEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = ""; }; 57 | D75726961DFFD3A000F0E3D6 /* GameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameView.swift; sourceTree = ""; }; 58 | D75726971DFFD3A000F0E3D6 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 59 | D75726A11DFFE89D00F0E3D6 /* README2.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README2.md; sourceTree = ""; }; 60 | D75726A21DFFE89D00F0E3D6 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 61 | D75726A51DFFEE5500F0E3D6 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = iOS/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 62 | D75726A81DFFF00C00F0E3D6 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = tvOS/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | B1D82CF41BC2F8CE00F4B330 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | B1D82D171BC3075C00F4B330 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | B1D82D461BC30A3800F4B330 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 309573F71990518F00B2ECED /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 3010A12519283C300006EB2D /* AVFoundation.framework */, 94 | 94CA7B8F1924A8D30005BA4B /* SceneKit.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | 94CA7B591924A8C30005BA4B = { 100 | isa = PBXGroup; 101 | children = ( 102 | D75726A21DFFE89D00F0E3D6 /* LICENSE.txt */, 103 | B1321A201DC9511F009C8FD1 /* README.md */, 104 | D75726A11DFFE89D00F0E3D6 /* README2.md */, 105 | 94CA7B651924A8C30005BA4B /* AVAEGamingExample */, 106 | B1D82D4A1BC30A3800F4B330 /* macOS */, 107 | B1D82CF81BC2F8CE00F4B330 /* iOS */, 108 | B1D82D1B1BC3075C00F4B330 /* tvOS */, 109 | 309573F71990518F00B2ECED /* Frameworks */, 110 | 94CA7B641924A8C30005BA4B /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 94CA7B641924A8C30005BA4B /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | B1D82CF71BC2F8CE00F4B330 /* AVAEGamingExample.app */, 118 | B1D82D1A1BC3075C00F4B330 /* AVAEGamingExample.app */, 119 | B1D82D491BC30A3800F4B330 /* AVAEGamingExample.app */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | 94CA7B651924A8C30005BA4B /* AVAEGamingExample */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | D75726951DFFD3A000F0E3D6 /* AudioEngine.swift */, 128 | D75726961DFFD3A000F0E3D6 /* GameView.swift */, 129 | D75726971DFFD3A000F0E3D6 /* GameViewController.swift */, 130 | B1D82D5D1BC30AA100F4B330 /* Assets */, 131 | ); 132 | path = AVAEGamingExample; 133 | sourceTree = ""; 134 | }; 135 | B1D82CF81BC2F8CE00F4B330 /* iOS */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | D75726A51DFFEE5500F0E3D6 /* AppDelegate.swift */, 139 | B1A3C57C1C179A65009C9FB6 /* Info.plist */, 140 | B1A3C57D1C179A65009C9FB6 /* LaunchScreen.storyboard */, 141 | B1A3C57F1C179A65009C9FB6 /* iOSMain.storyboard */, 142 | ); 143 | name = iOS; 144 | path = iOSAVAEGamingExample; 145 | sourceTree = ""; 146 | }; 147 | B1D82D1B1BC3075C00F4B330 /* tvOS */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | D75726A81DFFF00C00F0E3D6 /* AppDelegate.swift */, 151 | B1A3C58C1C179A89009C9FB6 /* Info.plist */, 152 | B1A3C58A1C179A89009C9FB6 /* tvOSMain.storyboard */, 153 | ); 154 | name = tvOS; 155 | path = tvOSAVAEGamingExample; 156 | sourceTree = ""; 157 | }; 158 | B1D82D4A1BC30A3800F4B330 /* macOS */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | D75726931DFFD38F00F0E3D6 /* AppDelegate.swift */, 162 | B1A3C5661C179A07009C9FB6 /* Info.plist */, 163 | B1A3C5641C179A07009C9FB6 /* macOSMain.storyboard */, 164 | ); 165 | path = macOS; 166 | sourceTree = ""; 167 | }; 168 | B1D82D5D1BC30AA100F4B330 /* Assets */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 3060564D192841990022B976 /* bounce.caf */, 172 | 30AD31B0192EC3120032BC30 /* launchSound.caf */, 173 | 94CA7B761924A8C30005BA4B /* Images.xcassets */, 174 | 94CA7B911924A91D0005BA4B /* assets.scnassets */, 175 | ); 176 | name = Assets; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXGroup section */ 180 | 181 | /* Begin PBXNativeTarget section */ 182 | B1D82CF61BC2F8CE00F4B330 /* iOS */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = B1D82D0B1BC2F8CE00F4B330 /* Build configuration list for PBXNativeTarget "iOS" */; 185 | buildPhases = ( 186 | B1D82CF31BC2F8CE00F4B330 /* Sources */, 187 | B1D82CF41BC2F8CE00F4B330 /* Frameworks */, 188 | B1D82CF51BC2F8CE00F4B330 /* Resources */, 189 | ); 190 | buildRules = ( 191 | ); 192 | dependencies = ( 193 | ); 194 | name = iOS; 195 | productName = iOSAVAEGamingExample; 196 | productReference = B1D82CF71BC2F8CE00F4B330 /* AVAEGamingExample.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | B1D82D191BC3075C00F4B330 /* tvOS */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = B1D82D2D1BC3075C00F4B330 /* Build configuration list for PBXNativeTarget "tvOS" */; 202 | buildPhases = ( 203 | B1D82D161BC3075C00F4B330 /* Sources */, 204 | B1D82D171BC3075C00F4B330 /* Frameworks */, 205 | B1D82D181BC3075C00F4B330 /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | ); 211 | name = tvOS; 212 | productName = tvOSAVAEGamingExample; 213 | productReference = B1D82D1A1BC3075C00F4B330 /* AVAEGamingExample.app */; 214 | productType = "com.apple.product-type.application"; 215 | }; 216 | B1D82D481BC30A3800F4B330 /* macOS */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = B1D82D5A1BC30A3800F4B330 /* Build configuration list for PBXNativeTarget "macOS" */; 219 | buildPhases = ( 220 | B1D82D451BC30A3800F4B330 /* Sources */, 221 | B1D82D461BC30A3800F4B330 /* Frameworks */, 222 | B1D82D471BC30A3800F4B330 /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | ); 228 | name = macOS; 229 | productName = OSXAVAEGamingExample; 230 | productReference = B1D82D491BC30A3800F4B330 /* AVAEGamingExample.app */; 231 | productType = "com.apple.product-type.application"; 232 | }; 233 | /* End PBXNativeTarget section */ 234 | 235 | /* Begin PBXProject section */ 236 | 94CA7B5A1924A8C30005BA4B /* Project object */ = { 237 | isa = PBXProject; 238 | attributes = { 239 | LastUpgradeCheck = 1020; 240 | ORGANIZATIONNAME = apple; 241 | TargetAttributes = { 242 | B1D82CF61BC2F8CE00F4B330 = { 243 | CreatedOnToolsVersion = 7.0; 244 | ProvisioningStyle = Automatic; 245 | }; 246 | B1D82D191BC3075C00F4B330 = { 247 | CreatedOnToolsVersion = 7.0; 248 | LastSwiftMigration = 1020; 249 | ProvisioningStyle = Automatic; 250 | }; 251 | B1D82D481BC30A3800F4B330 = { 252 | CreatedOnToolsVersion = 7.0; 253 | LastSwiftMigration = 0810; 254 | ProvisioningStyle = Automatic; 255 | }; 256 | }; 257 | }; 258 | buildConfigurationList = 94CA7B5D1924A8C30005BA4B /* Build configuration list for PBXProject "AVAEGamingExample" */; 259 | compatibilityVersion = "Xcode 3.2"; 260 | developmentRegion = en; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | en, 264 | Base, 265 | ); 266 | mainGroup = 94CA7B591924A8C30005BA4B; 267 | productRefGroup = 94CA7B641924A8C30005BA4B /* Products */; 268 | projectDirPath = ""; 269 | projectRoot = ""; 270 | targets = ( 271 | B1D82CF61BC2F8CE00F4B330 /* iOS */, 272 | B1D82D191BC3075C00F4B330 /* tvOS */, 273 | B1D82D481BC30A3800F4B330 /* macOS */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXResourcesBuildPhase section */ 279 | B1D82CF51BC2F8CE00F4B330 /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | B1D82D151BC3004900F4B330 /* assets.scnassets in Resources */, 284 | B1D82D0E1BC2FA4700F4B330 /* bounce.caf in Resources */, 285 | B1A3C5961C179AD1009C9FB6 /* LaunchScreen.storyboard in Resources */, 286 | B1A3C5951C179ACD009C9FB6 /* iOSMain.storyboard in Resources */, 287 | B1D82D0F1BC2FA4700F4B330 /* launchSound.caf in Resources */, 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | B1D82D181BC3075C00F4B330 /* Resources */ = { 292 | isa = PBXResourcesBuildPhase; 293 | buildActionMask = 2147483647; 294 | files = ( 295 | B1D82D681BC31C7100F4B330 /* bounce.caf in Resources */, 296 | B1D82D691BC31C7100F4B330 /* launchSound.caf in Resources */, 297 | B1A3C59D1C179AE7009C9FB6 /* tvOSMain.storyboard in Resources */, 298 | B1D82D6A1BC31C7100F4B330 /* assets.scnassets in Resources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | B1D82D471BC30A3800F4B330 /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | B1A3C5691C179A07009C9FB6 /* macOSMain.storyboard in Resources */, 307 | B1D82D5F1BC31C4000F4B330 /* bounce.caf in Resources */, 308 | B1D82D601BC31C4000F4B330 /* launchSound.caf in Resources */, 309 | B1D82D611BC31C4000F4B330 /* assets.scnassets in Resources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | /* End PBXResourcesBuildPhase section */ 314 | 315 | /* Begin PBXSourcesBuildPhase section */ 316 | B1D82CF31BC2F8CE00F4B330 /* Sources */ = { 317 | isa = PBXSourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | D75726A71DFFEEBE00F0E3D6 /* AppDelegate.swift in Sources */, 321 | D757269B1DFFD41000F0E3D6 /* AudioEngine.swift in Sources */, 322 | D757269F1DFFD5EB00F0E3D6 /* GameViewController.swift in Sources */, 323 | D757269D1DFFD5DD00F0E3D6 /* GameView.swift in Sources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | B1D82D161BC3075C00F4B330 /* Sources */ = { 328 | isa = PBXSourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | D75726AA1DFFF06000F0E3D6 /* AppDelegate.swift in Sources */, 332 | D757269C1DFFD41100F0E3D6 /* AudioEngine.swift in Sources */, 333 | D75726A01DFFD5ED00F0E3D6 /* GameViewController.swift in Sources */, 334 | D757269E1DFFD5DE00F0E3D6 /* GameView.swift in Sources */, 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | B1D82D451BC30A3800F4B330 /* Sources */ = { 339 | isa = PBXSourcesBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | D75726941DFFD38F00F0E3D6 /* AppDelegate.swift in Sources */, 343 | D757269A1DFFD3A000F0E3D6 /* GameViewController.swift in Sources */, 344 | D75726991DFFD3A000F0E3D6 /* GameView.swift in Sources */, 345 | D75726981DFFD3A000F0E3D6 /* AudioEngine.swift in Sources */, 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | }; 349 | /* End PBXSourcesBuildPhase section */ 350 | 351 | /* Begin PBXVariantGroup section */ 352 | B1A3C57D1C179A65009C9FB6 /* LaunchScreen.storyboard */ = { 353 | isa = PBXVariantGroup; 354 | children = ( 355 | B1A3C57E1C179A65009C9FB6 /* Base */, 356 | ); 357 | name = LaunchScreen.storyboard; 358 | sourceTree = ""; 359 | }; 360 | B1A3C57F1C179A65009C9FB6 /* iOSMain.storyboard */ = { 361 | isa = PBXVariantGroup; 362 | children = ( 363 | B1A3C5801C179A65009C9FB6 /* Base */, 364 | ); 365 | name = iOSMain.storyboard; 366 | sourceTree = ""; 367 | }; 368 | B1A3C58A1C179A89009C9FB6 /* tvOSMain.storyboard */ = { 369 | isa = PBXVariantGroup; 370 | children = ( 371 | B1A3C58B1C179A89009C9FB6 /* Base */, 372 | ); 373 | name = tvOSMain.storyboard; 374 | sourceTree = ""; 375 | }; 376 | /* End PBXVariantGroup section */ 377 | 378 | /* Begin XCBuildConfiguration section */ 379 | 94CA7B871924A8C30005BA4B /* Debug */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ALWAYS_SEARCH_USER_PATHS = NO; 383 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 384 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 385 | CLANG_CXX_LIBRARY = "libc++"; 386 | CLANG_ENABLE_MODULES = YES; 387 | CLANG_ENABLE_OBJC_ARC = YES; 388 | CLANG_WARN_ASSIGN_ENUM = NO; 389 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 390 | CLANG_WARN_BOOL_CONVERSION = YES; 391 | CLANG_WARN_COMMA = YES; 392 | CLANG_WARN_CONSTANT_CONVERSION = YES; 393 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 395 | CLANG_WARN_EMPTY_BODY = YES; 396 | CLANG_WARN_ENUM_CONVERSION = YES; 397 | CLANG_WARN_INFINITE_RECURSION = YES; 398 | CLANG_WARN_INT_CONVERSION = YES; 399 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 400 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 401 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 404 | CLANG_WARN_STRICT_PROTOTYPES = YES; 405 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 406 | CLANG_WARN_UNREACHABLE_CODE = YES; 407 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 408 | COPY_PHASE_STRIP = NO; 409 | ENABLE_STRICT_OBJC_MSGSEND = YES; 410 | ENABLE_TESTABILITY = YES; 411 | GCC_C_LANGUAGE_STANDARD = gnu99; 412 | GCC_DYNAMIC_NO_PIC = NO; 413 | GCC_NO_COMMON_BLOCKS = YES; 414 | GCC_OPTIMIZATION_LEVEL = 0; 415 | GCC_PREPROCESSOR_DEFINITIONS = ( 416 | "DEBUG=1", 417 | "$(inherited)", 418 | ); 419 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 420 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 421 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 422 | GCC_WARN_UNDECLARED_SELECTOR = YES; 423 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 424 | GCC_WARN_UNUSED_FUNCTION = YES; 425 | GCC_WARN_UNUSED_VARIABLE = YES; 426 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 427 | MACOSX_DEPLOYMENT_TARGET = 10.11; 428 | METAL_ENABLE_DEBUG_INFO = YES; 429 | ONLY_ACTIVE_ARCH = YES; 430 | PRODUCT_NAME = "${PROJECT_NAME}"; 431 | SDKROOT = macosx; 432 | SWIFT_VERSION = 3.0.1; 433 | }; 434 | name = Debug; 435 | }; 436 | 94CA7B881924A8C30005BA4B /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | buildSettings = { 439 | ALWAYS_SEARCH_USER_PATHS = NO; 440 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 442 | CLANG_CXX_LIBRARY = "libc++"; 443 | CLANG_ENABLE_MODULES = YES; 444 | CLANG_ENABLE_OBJC_ARC = YES; 445 | CLANG_WARN_ASSIGN_ENUM = NO; 446 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 447 | CLANG_WARN_BOOL_CONVERSION = YES; 448 | CLANG_WARN_COMMA = YES; 449 | CLANG_WARN_CONSTANT_CONVERSION = YES; 450 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 451 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 452 | CLANG_WARN_EMPTY_BODY = YES; 453 | CLANG_WARN_ENUM_CONVERSION = YES; 454 | CLANG_WARN_INFINITE_RECURSION = YES; 455 | CLANG_WARN_INT_CONVERSION = YES; 456 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 457 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 458 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 459 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 460 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 461 | CLANG_WARN_STRICT_PROTOTYPES = YES; 462 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | COPY_PHASE_STRIP = YES; 466 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 467 | ENABLE_NS_ASSERTIONS = NO; 468 | ENABLE_STRICT_OBJC_MSGSEND = YES; 469 | GCC_C_LANGUAGE_STANDARD = gnu99; 470 | GCC_NO_COMMON_BLOCKS = YES; 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 478 | MACOSX_DEPLOYMENT_TARGET = 10.11; 479 | METAL_ENABLE_DEBUG_INFO = NO; 480 | PRODUCT_NAME = "${PROJECT_NAME}"; 481 | SDKROOT = macosx; 482 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 483 | SWIFT_VERSION = 3.0.1; 484 | }; 485 | name = Release; 486 | }; 487 | B1D82D0C1BC2F8CE00F4B330 /* Debug */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 491 | DEBUG_INFORMATION_FORMAT = dwarf; 492 | DEVELOPMENT_TEAM = ""; 493 | ENABLE_TESTABILITY = YES; 494 | GCC_NO_COMMON_BLOCKS = YES; 495 | INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; 496 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 498 | MTL_ENABLE_DEBUG_INFO = YES; 499 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 500 | SDKROOT = iphoneos; 501 | SWIFT_VERSION = 5.0; 502 | TARGETED_DEVICE_FAMILY = "1,2"; 503 | }; 504 | name = Debug; 505 | }; 506 | B1D82D0D1BC2F8CE00F4B330 /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 510 | COPY_PHASE_STRIP = NO; 511 | DEVELOPMENT_TEAM = ""; 512 | GCC_NO_COMMON_BLOCKS = YES; 513 | INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; 514 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 516 | MTL_ENABLE_DEBUG_INFO = NO; 517 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 518 | SDKROOT = iphoneos; 519 | SWIFT_VERSION = 5.0; 520 | TARGETED_DEVICE_FAMILY = "1,2"; 521 | VALIDATE_PRODUCT = YES; 522 | }; 523 | name = Release; 524 | }; 525 | B1D82D2E1BC3075C00F4B330 /* Debug */ = { 526 | isa = XCBuildConfiguration; 527 | buildSettings = { 528 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 529 | DEVELOPMENT_TEAM = ""; 530 | ENABLE_TESTABILITY = YES; 531 | GCC_NO_COMMON_BLOCKS = YES; 532 | INFOPLIST_FILE = "$(SRCROOT)/tvOS/Info.plist"; 533 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 534 | MTL_ENABLE_DEBUG_INFO = YES; 535 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 536 | SDKROOT = appletvos; 537 | SWIFT_VERSION = 5.0; 538 | TARGETED_DEVICE_FAMILY = 3; 539 | TVOS_DEPLOYMENT_TARGET = 9.0; 540 | }; 541 | name = Debug; 542 | }; 543 | B1D82D2F1BC3075C00F4B330 /* Release */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | COPY_PHASE_STRIP = NO; 547 | DEVELOPMENT_TEAM = ""; 548 | GCC_NO_COMMON_BLOCKS = YES; 549 | INFOPLIST_FILE = "$(SRCROOT)/tvOS/Info.plist"; 550 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 551 | MTL_ENABLE_DEBUG_INFO = NO; 552 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 553 | SDKROOT = appletvos; 554 | SWIFT_VERSION = 5.0; 555 | TARGETED_DEVICE_FAMILY = 3; 556 | TVOS_DEPLOYMENT_TARGET = 9.0; 557 | VALIDATE_PRODUCT = YES; 558 | }; 559 | name = Release; 560 | }; 561 | B1D82D5B1BC30A3800F4B330 /* Debug */ = { 562 | isa = XCBuildConfiguration; 563 | buildSettings = { 564 | CLANG_ENABLE_MODULES = YES; 565 | CODE_SIGN_IDENTITY = "Mac Developer"; 566 | CODE_SIGN_STYLE = Automatic; 567 | COMBINE_HIDPI_IMAGES = YES; 568 | DEBUG_INFORMATION_FORMAT = dwarf; 569 | DEVELOPMENT_TEAM = ""; 570 | ENABLE_TESTABILITY = YES; 571 | GCC_NO_COMMON_BLOCKS = YES; 572 | INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; 573 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 574 | MACOSX_DEPLOYMENT_TARGET = 10.10; 575 | MTL_ENABLE_DEBUG_INFO = YES; 576 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 577 | PROVISIONING_PROFILE_SPECIFIER = ""; 578 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 579 | SWIFT_VERSION = 5.0; 580 | }; 581 | name = Debug; 582 | }; 583 | B1D82D5C1BC30A3800F4B330 /* Release */ = { 584 | isa = XCBuildConfiguration; 585 | buildSettings = { 586 | CLANG_ENABLE_MODULES = YES; 587 | CODE_SIGN_IDENTITY = "Mac Developer"; 588 | CODE_SIGN_STYLE = Automatic; 589 | COMBINE_HIDPI_IMAGES = YES; 590 | COPY_PHASE_STRIP = NO; 591 | DEVELOPMENT_TEAM = ""; 592 | GCC_NO_COMMON_BLOCKS = YES; 593 | INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; 594 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 595 | MACOSX_DEPLOYMENT_TARGET = 10.10; 596 | MTL_ENABLE_DEBUG_INFO = NO; 597 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.AVAEGamingExample"; 598 | PROVISIONING_PROFILE_SPECIFIER = ""; 599 | SWIFT_VERSION = 5.0; 600 | }; 601 | name = Release; 602 | }; 603 | /* End XCBuildConfiguration section */ 604 | 605 | /* Begin XCConfigurationList section */ 606 | 94CA7B5D1924A8C30005BA4B /* Build configuration list for PBXProject "AVAEGamingExample" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 94CA7B871924A8C30005BA4B /* Debug */, 610 | 94CA7B881924A8C30005BA4B /* Release */, 611 | ); 612 | defaultConfigurationIsVisible = 0; 613 | defaultConfigurationName = Release; 614 | }; 615 | B1D82D0B1BC2F8CE00F4B330 /* Build configuration list for PBXNativeTarget "iOS" */ = { 616 | isa = XCConfigurationList; 617 | buildConfigurations = ( 618 | B1D82D0C1BC2F8CE00F4B330 /* Debug */, 619 | B1D82D0D1BC2F8CE00F4B330 /* Release */, 620 | ); 621 | defaultConfigurationIsVisible = 0; 622 | defaultConfigurationName = Release; 623 | }; 624 | B1D82D2D1BC3075C00F4B330 /* Build configuration list for PBXNativeTarget "tvOS" */ = { 625 | isa = XCConfigurationList; 626 | buildConfigurations = ( 627 | B1D82D2E1BC3075C00F4B330 /* Debug */, 628 | B1D82D2F1BC3075C00F4B330 /* Release */, 629 | ); 630 | defaultConfigurationIsVisible = 0; 631 | defaultConfigurationName = Release; 632 | }; 633 | B1D82D5A1BC30A3800F4B330 /* Build configuration list for PBXNativeTarget "macOS" */ = { 634 | isa = XCConfigurationList; 635 | buildConfigurations = ( 636 | B1D82D5B1BC30A3800F4B330 /* Debug */, 637 | B1D82D5C1BC30A3800F4B330 /* Release */, 638 | ); 639 | defaultConfigurationIsVisible = 0; 640 | defaultConfigurationName = Release; 641 | }; 642 | /* End XCConfigurationList section */ 643 | }; 644 | rootObject = 94CA7B5A1924A8C30005BA4B /* Project object */; 645 | } 646 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/xcuserdata/dev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AVAEGamingExample.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | macOS.xcscheme 13 | 14 | orderHint 15 | 2 16 | 17 | tvOS.xcscheme 18 | 19 | orderHint 20 | 1 21 | 22 | 23 | SuppressBuildableAutocreation 24 | 25 | B1D82CF61BC2F8CE00F4B330 26 | 27 | primary 28 | 29 | 30 | B1D82D191BC3075C00F4B330 31 | 32 | primary 33 | 34 | 35 | B1D82D481BC30A3800F4B330 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /AVAEGamingExample/AudioEngine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | AudioEngine is the main controller class that manages the following: 7 | AVAudioEngine *_engine; 8 | AVAudioEnvironmentNode *_environment; 9 | AVAudioPCMBuffer *_collisionSoundBuffer; 10 | NSMutableArray *_collisionPlayerArray; 11 | AVAudioPlayerNode *_launchSoundPlayer; 12 | AVAudioPCMBuffer *_launchSoundBuffer; 13 | bool _multichannelOutputEnabled; 14 | 15 | It creates and connects all the nodes, loads the buffers as well as controls the AVAudioEngine object itself. 16 | */ 17 | 18 | @import Foundation; 19 | @import AVFoundation; 20 | @import SceneKit; 21 | 22 | @protocol AudioEngineDelegate 23 | 24 | @optional 25 | - (void)engineWasInterrupted; 26 | - (void)engineHasRestarted; 27 | - (void)engineConfigurationHasChanged; 28 | @end 29 | 30 | @interface AudioEngine : NSObject 31 | 32 | @property (weak) id delegate; 33 | @property (nonatomic, getter=isRunning) BOOL running; 34 | 35 | - (void)createPlayerForSCNNode:(SCNNode *)node; 36 | - (void)destroyPlayerForSCNNode:(SCNNode *)node; 37 | 38 | - (void)playCollisionSoundForSCNNode:(SCNNode *)node position:(AVAudio3DPoint)position impulse:(float)impulse; 39 | - (void)playLaunchSoundAtPosition:(AVAudio3DPoint)position completionHandler:(AVAudioNodeCompletionHandler)completionHandler; 40 | 41 | - (void)updateListenerPosition:(AVAudio3DPoint)position; 42 | - (void)updateListenerOrientation:(AVAudio3DAngularOrientation)orientation; 43 | 44 | -(AVAudio3DAngularOrientation)listenerAngularOrientation; 45 | -(AVAudio3DPoint)listenerPosition; 46 | 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /AVAEGamingExample/AudioEngine.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | AudioEngine is the main controller class that manages the following: 7 | AVAudioEngine *_engine; 8 | AVAudioEnvironmentNode *_environment; 9 | AVAudioPCMBuffer *_collisionSoundBuffer; 10 | NSMutableArray *_collisionPlayerArray; 11 | AVAudioPlayerNode *_launchSoundPlayer; 12 | AVAudioPCMBuffer *_launchSoundBuffer; 13 | bool _multichannelOutputEnabled; 14 | 15 | It creates and connects all the nodes, loads the buffers as well as controls the AVAudioEngine object itself. 16 | */ 17 | 18 | #import "AudioEngine.h" 19 | 20 | @interface AudioEngine () { 21 | AVAudioEngine *_engine; 22 | AVAudioEnvironmentNode *_environment; 23 | AVAudioPCMBuffer *_collisionSoundBuffer; 24 | NSMutableArray *_collisionPlayerArray; 25 | AVAudioPlayerNode *_launchSoundPlayer; 26 | AVAudioPCMBuffer *_launchSoundBuffer; 27 | bool _multichannelOutputEnabled; 28 | 29 | // mananging session and configuration changes 30 | BOOL _isSessionInterrupted; 31 | BOOL _isConfigChangePending; 32 | } 33 | @end 34 | 35 | @implementation AudioEngine 36 | 37 | - (AVAudioPCMBuffer *)loadSoundIntoBuffer:(NSString *)filename 38 | { 39 | NSError *error; 40 | BOOL success = NO; 41 | 42 | // load the collision sound into a buffer 43 | NSURL *soundFileURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:filename ofType:@"caf"]]; 44 | NSAssert(soundFileURL, @"Error creating URL to sound file"); 45 | 46 | AVAudioFile *soundFile = [[AVAudioFile alloc] initForReading:soundFileURL commonFormat:AVAudioPCMFormatFloat32 interleaved:NO error:&error]; 47 | NSAssert(soundFile != nil, @"Error creating soundFile, %@", error.localizedDescription); 48 | 49 | AVAudioPCMBuffer *outputBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:soundFile.processingFormat frameCapacity:(AVAudioFrameCount)soundFile.length]; 50 | success = [soundFile readIntoBuffer:outputBuffer error:&error]; 51 | NSAssert(success, @"Error reading file into buffer, %@", error.localizedDescription); 52 | 53 | return outputBuffer; 54 | } 55 | 56 | - (BOOL)isRunning 57 | { 58 | return _engine.isRunning; 59 | } 60 | 61 | - (instancetype)init 62 | { 63 | if (self = [super init]) { 64 | 65 | #if TARGET_OS_IOS || TARGET_OS_SIMULATOR 66 | [self initAVAudioSession]; 67 | #endif 68 | _isSessionInterrupted = NO; 69 | _isConfigChangePending = NO; 70 | 71 | _engine = [[AVAudioEngine alloc] init]; 72 | _environment = [[AVAudioEnvironmentNode alloc] init]; 73 | [_engine attachNode:_environment]; 74 | 75 | // array that keeps track of all the collision players 76 | _collisionPlayerArray = [[NSMutableArray alloc] init]; 77 | 78 | // load the collision sound into a buffer 79 | _collisionSoundBuffer = [self loadSoundIntoBuffer:@"bounce"]; 80 | 81 | // load the launch sound into a buffer 82 | _launchSoundBuffer = [self loadSoundIntoBuffer:@"launchSound"]; 83 | 84 | // setup the launch sound player 85 | _launchSoundPlayer = [[AVAudioPlayerNode alloc] init]; 86 | [_engine attachNode:_launchSoundPlayer]; 87 | _launchSoundPlayer.volume = 0.35; 88 | 89 | // wire everything up 90 | [self makeEngineConnections]; 91 | 92 | // sign up for notifications about changes in output configuration 93 | [[NSNotificationCenter defaultCenter] addObserverForName:AVAudioEngineConfigurationChangeNotification object:_engine queue:nil usingBlock: ^(NSNotification *note) { 94 | 95 | // if we've received this notification, something has changed and the engine has been stopped 96 | // re-wire all the connections and start the engine 97 | 98 | _isConfigChangePending = YES; 99 | 100 | if (!_isSessionInterrupted) { 101 | NSLog(@"Received a %@ notification!", AVAudioEngineConfigurationChangeNotification); 102 | NSLog(@"Re-wiring connections and starting once again"); 103 | [self makeEngineConnections]; 104 | [self startEngine]; 105 | } 106 | else { 107 | NSLog(@"Session is interrupted, deferring changes"); 108 | } 109 | 110 | // post notification 111 | if ([self.delegate respondsToSelector:@selector(engineConfigurationHasChanged)]) { 112 | [self.delegate engineConfigurationHasChanged]; 113 | } 114 | }]; 115 | 116 | // turn on the environment reverb 117 | _environment.reverbParameters.enable = YES; 118 | _environment.reverbParameters.level = -20.0; 119 | [_environment.reverbParameters loadFactoryReverbPreset:AVAudioUnitReverbPresetLargeHall]; 120 | 121 | // we're ready to start rendering so start the engine 122 | [self startEngine]; 123 | } 124 | return self; 125 | } 126 | 127 | - (void)makeEngineConnections 128 | { 129 | [_engine connect:_launchSoundPlayer to:_environment format:_launchSoundBuffer.format]; 130 | [_engine connect:_environment to:_engine.outputNode format:[self constructOutputConnectionFormatForEnvironment]]; 131 | 132 | // if we're connecting with a multichannel format, we need to pick a multichannel rendering algorithm 133 | AVAudio3DMixingRenderingAlgorithm renderingAlgo = _multichannelOutputEnabled ? AVAudio3DMixingRenderingAlgorithmSoundField : AVAudio3DMixingRenderingAlgorithmEqualPowerPanning; 134 | 135 | // if we already have a pool of collision players, connect all of them to the environment 136 | for (int i = 0; i < _collisionPlayerArray.count; i++) { 137 | [_engine connect:_collisionPlayerArray[i] to:_environment format:_collisionSoundBuffer.format]; 138 | _collisionPlayerArray[i].renderingAlgorithm = renderingAlgo; 139 | } 140 | } 141 | 142 | - (void)startEngine 143 | { 144 | NSError *error; 145 | BOOL success = NO; 146 | success = [_engine startAndReturnError:&error]; 147 | NSAssert(success, @"Error starting engine, %@", error.localizedDescription); 148 | } 149 | 150 | - (AVAudioFormat *)constructOutputConnectionFormatForEnvironment 151 | { 152 | AVAudioFormat *environmentOutputConnectionFormat = nil; 153 | AVAudioChannelCount numHardwareOutputChannels = [_engine.outputNode outputFormatForBus:0].channelCount; 154 | const double hardwareSampleRate = [_engine.outputNode outputFormatForBus:0].sampleRate; 155 | 156 | // if we're connected to multichannel hardware, create a compatible multichannel format for the environment node 157 | if (numHardwareOutputChannels > 2 && numHardwareOutputChannels != 3) { 158 | if (numHardwareOutputChannels > 8) numHardwareOutputChannels = 8; 159 | 160 | // find an AudioChannelLayoutTag that the environment node knows how to render to 161 | // this is documented in AVAudioEnvironmentNode.h 162 | AudioChannelLayoutTag environmentOutputLayoutTag; 163 | switch (numHardwareOutputChannels) { 164 | case 4: 165 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_4; 166 | break; 167 | 168 | case 5: 169 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_0; 170 | break; 171 | 172 | case 6: 173 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_6_0; 174 | break; 175 | 176 | case 7: 177 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_0; 178 | break; 179 | 180 | case 8: 181 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_8; 182 | break; 183 | 184 | default: 185 | // based on our logic, we shouldn't hit this case 186 | environmentOutputLayoutTag = kAudioChannelLayoutTag_Stereo; 187 | break; 188 | } 189 | 190 | // using that layout tag, now construct a format 191 | AVAudioChannelLayout *environmentOutputChannelLayout = [[AVAudioChannelLayout alloc] initWithLayoutTag:environmentOutputLayoutTag]; 192 | environmentOutputConnectionFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:hardwareSampleRate channelLayout:environmentOutputChannelLayout]; 193 | _multichannelOutputEnabled = true; 194 | } 195 | else { 196 | // stereo rendering format, this is the common case 197 | environmentOutputConnectionFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:hardwareSampleRate channels:2]; 198 | _multichannelOutputEnabled = false; 199 | } 200 | 201 | return environmentOutputConnectionFormat; 202 | } 203 | 204 | - (void)createPlayerForSCNNode:(SCNNode *)node 205 | { 206 | // create a new player and connect it to the environment node 207 | AVAudioPlayerNode *newPlayer = [[AVAudioPlayerNode alloc] init]; 208 | [_engine attachNode:newPlayer]; 209 | [_engine connect:newPlayer to:_environment format:_collisionSoundBuffer.format]; 210 | [_collisionPlayerArray insertObject:newPlayer atIndex:[node.name integerValue]]; 211 | 212 | // pick a rendering algorithm based on the rendering format 213 | AVAudio3DMixingRenderingAlgorithm renderingAlgo = _multichannelOutputEnabled ? AVAudio3DMixingRenderingAlgorithmSoundField : AVAudio3DMixingRenderingAlgorithmEqualPowerPanning; 214 | newPlayer.renderingAlgorithm = renderingAlgo; 215 | 216 | // turn up the reverb blend for this player 217 | newPlayer.reverbBlend = 0.3; 218 | } 219 | 220 | - (void)destroyPlayerForSCNNode:(SCNNode *)node 221 | { 222 | NSInteger playerIndex = [node.name integerValue]; 223 | AVAudioPlayerNode *player = _collisionPlayerArray[playerIndex]; 224 | [player stop]; 225 | [_engine disconnectNodeOutput:player]; 226 | } 227 | 228 | - (void)playCollisionSoundForSCNNode:(SCNNode *)node position:(AVAudio3DPoint)position impulse:(float)impulse 229 | { 230 | if (_engine.isRunning) { 231 | NSInteger playerIndex = [node.name integerValue]; 232 | AVAudioPlayerNode *player = _collisionPlayerArray[playerIndex]; 233 | [player scheduleBuffer:_collisionSoundBuffer atTime:nil options:AVAudioPlayerNodeBufferInterrupts completionHandler:nil]; 234 | player.position = position; 235 | player.volume = [self calculateVolumeForImpulse:impulse]; 236 | player.rate = [self calculatePlaybackRateForImpulse:impulse]; 237 | [player play]; 238 | } 239 | } 240 | 241 | - (void)playLaunchSoundAtPosition:(AVAudio3DPoint)position completionHandler:(AVAudioNodeCompletionHandler)completionHandler 242 | { 243 | if (_engine.isRunning) { 244 | _launchSoundPlayer.position = position; 245 | [_launchSoundPlayer scheduleBuffer:_launchSoundBuffer completionHandler:completionHandler]; 246 | [_launchSoundPlayer play]; 247 | } 248 | } 249 | 250 | - (float)calculateVolumeForImpulse:(float)impulse 251 | { 252 | // Simple mapping of impulse to volume 253 | 254 | const float volMinDB = -20.; 255 | const float impulseMax = 12.; 256 | 257 | if (impulse > impulseMax) impulse = impulseMax; 258 | float volDB = (impulse / impulseMax * -volMinDB) + volMinDB; 259 | return powf(10, (volDB / 20)); 260 | } 261 | 262 | - (float)calculatePlaybackRateForImpulse:(float)impulse 263 | { 264 | // Simple mapping of impulse to playback rate (pitch) 265 | // This gives the effect of the pitch dropping as the impulse reduces 266 | 267 | const float rateMax = 1.2; 268 | const float rateMin = 0.95; 269 | const float rateRange = rateMax - rateMin; 270 | const float impulseMax = 12.; 271 | const float impulseMin = 0.6; 272 | const float impulseRange = impulseMax - impulseMin; 273 | 274 | if (impulse > impulseMax) impulse = impulseMax; 275 | if (impulse < impulseMin) impulse = impulseMin; 276 | 277 | return (((impulse - impulseMin) / impulseRange) * rateRange) + rateMin; 278 | } 279 | 280 | - (void)updateListenerPosition:(AVAudio3DPoint)position 281 | { 282 | _environment.listenerPosition = position; 283 | } 284 | 285 | - (AVAudio3DPoint)listenerPosition 286 | { 287 | return _environment.listenerPosition; 288 | } 289 | 290 | - (void)updateListenerOrientation:(AVAudio3DAngularOrientation)orientation 291 | { 292 | _environment.listenerAngularOrientation = orientation; 293 | } 294 | 295 | - (AVAudio3DAngularOrientation)listenerAngularOrientation 296 | { 297 | return _environment.listenerAngularOrientation; 298 | } 299 | 300 | #pragma mark AVAudioSession 301 | 302 | #if TARGET_OS_IOS || TARGET_OS_SIMULATOR 303 | - (void)initAVAudioSession 304 | { 305 | NSError *error; 306 | 307 | // Configure the audio session 308 | AVAudioSession *sessionInstance = [AVAudioSession sharedInstance]; 309 | 310 | // set the session category 311 | bool success = [sessionInstance setCategory:AVAudioSessionCategoryPlayback error:&error]; 312 | if (!success) NSLog(@"Error setting AVAudioSession category! %@\n", [error localizedDescription]); 313 | 314 | const NSInteger desiredNumChannels = 8; // for 7.1 rendering 315 | const NSInteger maxChannels = sessionInstance.maximumOutputNumberOfChannels; 316 | if (maxChannels >= desiredNumChannels) { 317 | success = [sessionInstance setPreferredOutputNumberOfChannels:desiredNumChannels error:&error]; 318 | if (!success) NSLog(@"Error setting PreferredOuputNumberOfChannels! %@", [error localizedDescription]); 319 | } 320 | 321 | 322 | // add interruption handler 323 | [[NSNotificationCenter defaultCenter] addObserver:self 324 | selector:@selector(handleInterruption:) 325 | name:AVAudioSessionInterruptionNotification 326 | object:sessionInstance]; 327 | 328 | // we don't do anything special in the route change notification 329 | [[NSNotificationCenter defaultCenter] addObserver:self 330 | selector:@selector(handleRouteChange:) 331 | name:AVAudioSessionRouteChangeNotification 332 | object:sessionInstance]; 333 | 334 | [[NSNotificationCenter defaultCenter] addObserver:self 335 | selector:@selector(handleMediaServicesReset:) 336 | name:AVAudioSessionMediaServicesWereResetNotification 337 | object:sessionInstance]; 338 | 339 | // activate the audio session 340 | success = [sessionInstance setActive:YES error:&error]; 341 | if (!success) NSLog(@"Error setting session active! %@\n", [error localizedDescription]); 342 | } 343 | 344 | - (void)handleInterruption:(NSNotification *)notification 345 | { 346 | UInt8 theInterruptionType = [[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue]; 347 | 348 | NSLog(@"Session interrupted > --- %s ---\n", theInterruptionType == AVAudioSessionInterruptionTypeBegan ? "Begin Interruption" : "End Interruption"); 349 | 350 | if (theInterruptionType == AVAudioSessionInterruptionTypeBegan) { 351 | _isSessionInterrupted = YES; 352 | 353 | //stop the playback of the nodes 354 | for (int i = 0; i < _collisionPlayerArray.count; i++) 355 | [[_collisionPlayerArray objectAtIndex:i] stop]; 356 | 357 | if ([self.delegate respondsToSelector:@selector(engineWasInterrupted)]) { 358 | [self.delegate engineWasInterrupted]; 359 | } 360 | 361 | } 362 | if (theInterruptionType == AVAudioSessionInterruptionTypeEnded) { 363 | // make sure to activate the session 364 | NSError *error; 365 | bool success = [[AVAudioSession sharedInstance] setActive:YES error:&error]; 366 | if (!success) 367 | NSLog(@"AVAudioSession set active failed with error: %@", [error localizedDescription]); 368 | else { 369 | _isSessionInterrupted = NO; 370 | if (_isConfigChangePending) { 371 | //there is a pending config changed notification 372 | NSLog(@"Responding to earlier engine config changed notification. Re-wiring connections and starting once again"); 373 | [self makeEngineConnections]; 374 | [self startEngine]; 375 | 376 | _isConfigChangePending = NO; 377 | } 378 | else { 379 | // start the engine once again 380 | [self startEngine]; 381 | } 382 | } 383 | } 384 | } 385 | 386 | - (void)handleRouteChange:(NSNotification *)notification 387 | { 388 | UInt8 reasonValue = [[notification.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] intValue]; 389 | AVAudioSessionRouteDescription *routeDescription = [notification.userInfo valueForKey:AVAudioSessionRouteChangePreviousRouteKey]; 390 | 391 | NSLog(@"Route change:"); 392 | switch (reasonValue) { 393 | case AVAudioSessionRouteChangeReasonNewDeviceAvailable: 394 | NSLog(@" NewDeviceAvailable"); 395 | break; 396 | case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: 397 | NSLog(@" OldDeviceUnavailable"); 398 | break; 399 | case AVAudioSessionRouteChangeReasonCategoryChange: 400 | NSLog(@" CategoryChange"); 401 | NSLog(@" New Category: %@", [[AVAudioSession sharedInstance] category]); 402 | break; 403 | case AVAudioSessionRouteChangeReasonOverride: 404 | NSLog(@" Override"); 405 | break; 406 | case AVAudioSessionRouteChangeReasonWakeFromSleep: 407 | NSLog(@" WakeFromSleep"); 408 | break; 409 | case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: 410 | NSLog(@" NoSuitableRouteForCategory"); 411 | break; 412 | default: 413 | NSLog(@" ReasonUnknown"); 414 | } 415 | 416 | NSLog(@"Previous route:\n"); 417 | NSLog(@"%@", routeDescription); 418 | } 419 | 420 | - (void)handleMediaServicesReset:(NSNotification *)notification 421 | { 422 | // if we've received this notification, the media server has been reset 423 | // re-wire all the connections and start the engine 424 | NSLog(@"Media services have been reset!"); 425 | NSLog(@"Re-wiring connections and starting once again"); 426 | 427 | [self initAVAudioSession]; 428 | [self createEngineAndAttachNodes]; 429 | [self makeEngineConnections]; 430 | [self startEngine]; 431 | 432 | //notify the delegate 433 | if ([self.delegate respondsToSelector:@selector(engineConfigurationHasChanged)]) { 434 | [self.delegate engineConfigurationHasChanged]; 435 | } 436 | } 437 | 438 | - (void)createEngineAndAttachNodes 439 | { 440 | _engine = [[AVAudioEngine alloc] init]; 441 | 442 | [_engine attachNode:_environment]; 443 | [_engine attachNode:_launchSoundPlayer]; 444 | 445 | for (int i = 0; i < _collisionPlayerArray.count; i++) 446 | [_engine attachNode:[_collisionPlayerArray objectAtIndex:i]]; 447 | 448 | } 449 | 450 | #endif 451 | 452 | 453 | @end 454 | -------------------------------------------------------------------------------- /AVAEGamingExample/AudioEngine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AudioEngine.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2015/4/20. 6 | // 7 | /* 8 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 9 | See LICENSE.txt for this sample’s licensing information 10 | 11 | Abstract: 12 | AudioEngine is the main controller class that manages the following: 13 | AVAudioEngine *_engine; 14 | AVAudioEnvironmentNode *_environment; 15 | AVAudioPCMBuffer *_collisionSoundBuffer; 16 | NSMutableArray *_collisionPlayerArray; 17 | AVAudioPlayerNode *_launchSoundPlayer; 18 | AVAudioPCMBuffer *_launchSoundBuffer; 19 | bool _multichannelOutputEnabled; 20 | 21 | It creates and connects all the nodes, loads the buffers as well as controls the AVAudioEngine object itself. 22 | */ 23 | 24 | import Foundation 25 | import AVFoundation 26 | import SceneKit 27 | 28 | @objc protocol AudioEngineDelegate: NSObjectProtocol { 29 | 30 | @objc optional func engineWasInterrupted() 31 | @objc optional func engineHasRestarted() 32 | @objc optional func engineConfigurationHasChanged() 33 | } 34 | 35 | @objc(AudioEngine) 36 | class AudioEngine: NSObject { 37 | 38 | weak var delegate: AudioEngineDelegate? 39 | 40 | private var _engine: AVAudioEngine 41 | private var _environment: AVAudioEnvironmentNode 42 | private var _collisionSoundBuffer: AVAudioPCMBuffer 43 | private var _collisionPlayerArray: [AVAudioPlayerNode] = [] 44 | private var _launchSoundPlayer: AVAudioPlayerNode 45 | private var _launchSoundBuffer: AVAudioPCMBuffer 46 | private var _multichannelOutputEnabled: Bool = false 47 | 48 | // mananging session and configuration changes 49 | private var _isSessionInterrupted: Bool = false 50 | private var _isConfigChangePending: Bool = false 51 | 52 | private class func loadSoundIntoBuffer(_ filename: String) -> AVAudioPCMBuffer { 53 | 54 | // load the collision sound into a buffer 55 | let soundFileURL = URL(string: Bundle.main.path(forResource: filename, ofType: "caf")!) 56 | assert(soundFileURL != nil, "Error creating URL to sound file") 57 | 58 | let soundFile: AVAudioFile! 59 | do { 60 | soundFile = try AVAudioFile(forReading: soundFileURL!, commonFormat: AVAudioCommonFormat.pcmFormatFloat32, interleaved: false) 61 | } catch let error as NSError { 62 | //soundFile = nil 63 | fatalError("Error creating soundFile, \(error.localizedDescription)") 64 | } 65 | 66 | let outputBuffer = AVAudioPCMBuffer(pcmFormat: soundFile!.processingFormat, frameCapacity: AVAudioFrameCount(soundFile!.length))! 67 | do { 68 | try soundFile!.read(into: outputBuffer) 69 | } catch let error as NSError { 70 | fatalError("Error reading file into buffer, \(error.localizedDescription)") 71 | } 72 | 73 | return outputBuffer 74 | } 75 | 76 | var isRunning: Bool { 77 | get { 78 | return _engine.isRunning; 79 | } 80 | set { 81 | //ignored 82 | } 83 | } 84 | 85 | override init() { 86 | _engine = AVAudioEngine() 87 | _environment = AVAudioEnvironmentNode() 88 | 89 | // array that keeps track of all the collision players 90 | 91 | // load the collision sound into a buffer 92 | _collisionSoundBuffer = AudioEngine.loadSoundIntoBuffer("bounce") 93 | 94 | // load the launch sound into a buffer 95 | _launchSoundBuffer = AudioEngine.loadSoundIntoBuffer("launchSound") 96 | 97 | // setup the launch sound player 98 | _launchSoundPlayer = AVAudioPlayerNode() 99 | super.init() 100 | 101 | #if os(iOS) 102 | self.initAVAudioSession() 103 | #endif 104 | 105 | _engine.attach(_environment) 106 | _engine.attach(_launchSoundPlayer) 107 | _launchSoundPlayer.volume = 0.35 108 | 109 | // wire everything up 110 | self.makeEngineConnections() 111 | 112 | // sign up for notifications about changes in output configuration 113 | NotificationCenter.default.addObserver(forName: NSNotification.Name.AVAudioEngineConfigurationChange, object: _engine, queue: nil) {note in 114 | 115 | // if we've received this notification, something has changed and the engine has been stopped 116 | // re-wire all the connections and start the engine 117 | 118 | self._isConfigChangePending = true 119 | 120 | if !self._isSessionInterrupted { 121 | NSLog("Received a \(Notification.Name.AVAudioEngineConfigurationChange) notification!") 122 | NSLog("Re-wiring connections and starting once again") 123 | self.makeEngineConnections() 124 | self.startEngine() 125 | } else { 126 | NSLog("Session is interrupted, deferring changes") 127 | } 128 | 129 | // post notification 130 | self.delegate?.engineConfigurationHasChanged?() 131 | } 132 | 133 | // turn on the environment reverb 134 | _environment.reverbParameters.enable = true 135 | _environment.reverbParameters.level = -20.0 136 | _environment.reverbParameters.loadFactoryReverbPreset(AVAudioUnitReverbPreset.largeHall) 137 | 138 | // we're ready to start rendering so start the engine 139 | self.startEngine() 140 | } 141 | 142 | private func makeEngineConnections() { 143 | _engine.connect(_launchSoundPlayer, to: _environment, format: _launchSoundBuffer.format) 144 | _engine.connect(_environment, to: _engine.outputNode, format: self.constructOutputConnectionFormatForEnvironment()) 145 | 146 | // if we're connecting with a multichannel format, we need to pick a multichannel rendering algorithm 147 | let renderingAlgo: AVAudio3DMixingRenderingAlgorithm = _multichannelOutputEnabled ? .soundField : .equalPowerPanning 148 | 149 | // if we already have a pool of collision players, connect all of them to the environment 150 | for collisionPlayer in _collisionPlayerArray { 151 | _engine.connect(collisionPlayer, to: _environment, format: _collisionSoundBuffer.format) 152 | collisionPlayer.renderingAlgorithm = renderingAlgo 153 | } 154 | } 155 | 156 | private func startEngine() { 157 | do { 158 | try _engine.start() 159 | } catch let error as NSError { 160 | fatalError("Error starting engine, \(error.localizedDescription)") 161 | } 162 | } 163 | 164 | private func constructOutputConnectionFormatForEnvironment() -> AVAudioFormat { 165 | let environmentOutputConnectionFormat: AVAudioFormat 166 | let numHardwareOutputChannels = _engine.outputNode.outputFormat(forBus: 0).channelCount 167 | let hardwareSampleRate = _engine.outputNode.outputFormat(forBus: 0).sampleRate 168 | 169 | // if we're connected to multichannel hardware, create a compatible multichannel format for the environment node 170 | if numHardwareOutputChannels > 2 && numHardwareOutputChannels != 3 { 171 | 172 | // find an AudioChannelLayoutTag that the environment node knows how to render to 173 | // this is documented in AVAudioEnvironmentNode.h 174 | let environmentOutputLayoutTag: AudioChannelLayoutTag 175 | switch numHardwareOutputChannels { 176 | case 4: 177 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_4 178 | 179 | case 5: 180 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_0 181 | 182 | case 6: 183 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_6_0 184 | 185 | case 7: 186 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_0 187 | 188 | case 8: 189 | environmentOutputLayoutTag = kAudioChannelLayoutTag_AudioUnit_8 190 | 191 | default: 192 | // based on our logic, we shouldn't hit this case 193 | environmentOutputLayoutTag = kAudioChannelLayoutTag_Stereo 194 | } 195 | 196 | // using that layout tag, now construct a format 197 | let environmentOutputChannelLayout = AVAudioChannelLayout(layoutTag: environmentOutputLayoutTag) 198 | environmentOutputConnectionFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareSampleRate, channelLayout: environmentOutputChannelLayout!) 199 | _multichannelOutputEnabled = true 200 | } else { 201 | // stereo rendering format, this is the common case 202 | environmentOutputConnectionFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareSampleRate, channels: 2)! 203 | _multichannelOutputEnabled = false 204 | } 205 | 206 | return environmentOutputConnectionFormat 207 | } 208 | 209 | func createPlayerForSCNNode(_ node: SCNNode) { 210 | // create a new player and connect it to the environment node 211 | let newPlayer = AVAudioPlayerNode() 212 | _engine.attach(newPlayer) 213 | _engine.connect(newPlayer, to: _environment, format: _collisionSoundBuffer.format) 214 | _collisionPlayerArray.insert(newPlayer, at: Int(node.name!)!) 215 | 216 | // pick a rendering algorithm based on the rendering format 217 | let renderingAlgo: AVAudio3DMixingRenderingAlgorithm = _multichannelOutputEnabled ? 218 | .soundField : 219 | .equalPowerPanning 220 | 221 | newPlayer.renderingAlgorithm = renderingAlgo 222 | 223 | // turn up the reverb blend for this player 224 | newPlayer.reverbBlend = 0.3 225 | } 226 | 227 | func destroyPlayerForSCNNode(_ node: SCNNode) { 228 | let playerIndex = Int(node.name!)! 229 | let player = _collisionPlayerArray[playerIndex] 230 | player.stop() 231 | _engine.disconnectNodeOutput(player) 232 | } 233 | 234 | func playCollisionSoundForSCNNode(_ node: SCNNode, position: AVAudio3DPoint, impulse: Float) { 235 | if _engine.isRunning { 236 | let playerIndex = Int(node.name!)! 237 | let player = _collisionPlayerArray[playerIndex] 238 | player.scheduleBuffer(_collisionSoundBuffer, at: nil, options: AVAudioPlayerNodeBufferOptions.interrupts, completionHandler: nil) 239 | player.position = position 240 | player.volume = self.calculateVolumeForImpulse(impulse) 241 | player.rate = self.calculatePlaybackRateForImpulse(impulse) 242 | player.play() 243 | } 244 | } 245 | 246 | func playLaunchSoundAtPosition(_ position: AVAudio3DPoint, completionHandler: @escaping AVAudioNodeCompletionHandler) { 247 | if _engine.isRunning { 248 | _launchSoundPlayer.position = position 249 | _launchSoundPlayer.scheduleBuffer(_launchSoundBuffer, completionHandler: completionHandler) 250 | _launchSoundPlayer.play() 251 | } 252 | } 253 | 254 | private func calculateVolumeForImpulse(_ _impulse: Float) -> Float { 255 | // Simple mapping of impulse to volume 256 | 257 | let volMinDB: Float = -20.0 258 | let impulseMax: Float = 12.0 259 | 260 | var impulse = _impulse 261 | if impulse > impulseMax { impulse = impulseMax } 262 | let volDB = (impulse / impulseMax * -volMinDB) + volMinDB 263 | return powf(10, (volDB / 20)) 264 | } 265 | 266 | private func calculatePlaybackRateForImpulse(_ _impulse: Float) -> Float { 267 | // Simple mapping of impulse to playback rate (pitch) 268 | // This gives the effect of the pitch dropping as the impulse reduces 269 | 270 | let rateMax: Float = 1.2 271 | let rateMin: Float = 0.95 272 | let rateRange: Float = rateMax - rateMin 273 | let impulseMax: Float = 12.0 274 | let impulseMin: Float = 0.6 275 | let impulseRange: Float = impulseMax - impulseMin 276 | 277 | var impulse = _impulse 278 | if impulse > impulseMax { impulse = impulseMax } 279 | if impulse < impulseMin { impulse = impulseMin } 280 | 281 | return (((impulse - impulseMin) / impulseRange) * rateRange) + rateMin 282 | } 283 | 284 | func updateListenerPosition(_ position: AVAudio3DPoint) { 285 | _environment.listenerPosition = position; 286 | } 287 | 288 | var listenerPosition: AVAudio3DPoint { 289 | return _environment.listenerPosition; 290 | } 291 | 292 | func updateListenerOrientation(_ orientation: AVAudio3DAngularOrientation) { 293 | _environment.listenerAngularOrientation = orientation 294 | } 295 | 296 | var listenerAngularOrientation: AVAudio3DAngularOrientation { 297 | return _environment.listenerAngularOrientation; 298 | } 299 | 300 | //MARK: AVAudioSession 301 | 302 | #if os(iOS) || os(tvOS) 303 | private func initAVAudioSession() { 304 | 305 | // Configure the audio session 306 | let sessionInstance = AVAudioSession.sharedInstance() 307 | 308 | // set the session category 309 | do { 310 | if #available(iOS 10.0, tvOS 10.0, *) { 311 | try sessionInstance.setCategory(.playback, mode: .default) 312 | } else { 313 | try sessionInstance.setCategory(.playback) 314 | } 315 | } catch let error as NSError { 316 | NSLog("Error setting AVAudioSession category! \(error.localizedDescription)\n") 317 | } 318 | 319 | let desiredNumChannels = 8 // for 7.1 rendering 320 | let maxChannels = sessionInstance.maximumOutputNumberOfChannels 321 | if maxChannels >= desiredNumChannels { 322 | do { 323 | try sessionInstance.setPreferredOutputNumberOfChannels(desiredNumChannels) 324 | } catch let error as NSError { 325 | NSLog("Error setting PreferredOuputNumberOfChannels! \(error.localizedDescription)") 326 | } 327 | } 328 | 329 | 330 | // add interruption handler 331 | NotificationCenter.default.addObserver( 332 | self, 333 | selector: #selector(handleInterruption), 334 | name: AVAudioSession.interruptionNotification, 335 | object: sessionInstance) 336 | 337 | // we don't do anything special in the route change notification 338 | NotificationCenter.default.addObserver( 339 | self, 340 | selector: #selector(handleRouteChange), 341 | name: AVAudioSession.routeChangeNotification, 342 | object: sessionInstance) 343 | 344 | NotificationCenter.default.addObserver( 345 | self, 346 | selector: #selector(handleMediaServicesReset), 347 | name: AVAudioSession.mediaServicesWereResetNotification, 348 | object: sessionInstance) 349 | 350 | // activate the audio session 351 | do { 352 | try sessionInstance.setActive(true) 353 | } catch let error as NSError { 354 | NSLog("Error setting session active! \(error.localizedDescription)\n") 355 | } 356 | } 357 | 358 | @objc private func handleInterruption(_ notification: NSNotification) { 359 | let theInterruptionType = notification.userInfo![AVAudioSessionInterruptionTypeKey].flatMap { 360 | AVAudioSession.InterruptionType(rawValue: $0 as! UInt) 361 | } 362 | 363 | NSLog("Session interrupted > --- %s ---\n", theInterruptionType == AVAudioSession.InterruptionType.began ? "Begin Interruption" : "End Interruption") 364 | 365 | if theInterruptionType == AVAudioSession.InterruptionType.began { 366 | _isSessionInterrupted = true 367 | 368 | //stop the playback of the nodes 369 | for collisionPlayer in _collisionPlayerArray { 370 | collisionPlayer.stop() 371 | } 372 | 373 | self.delegate?.engineWasInterrupted?() 374 | 375 | } 376 | if theInterruptionType == AVAudioSession.InterruptionType.ended { 377 | // make sure to activate the session 378 | do { 379 | try AVAudioSession.sharedInstance().setActive(true) 380 | _isSessionInterrupted = false 381 | if _isConfigChangePending { 382 | //there is a pending config changed notification 383 | NSLog("Responding to earlier engine config changed notification. Re-wiring connections and starting once again"); 384 | self.makeEngineConnections() 385 | self.startEngine() 386 | 387 | _isConfigChangePending = false 388 | } else { 389 | // start the engine once again 390 | self.startEngine() 391 | } 392 | } catch let error as NSError { 393 | NSLog("AVAudioSession set active failed with error: %@", error.localizedDescription) 394 | } 395 | } 396 | } 397 | 398 | @objc private func handleRouteChange(_ notification: NSNotification) { 399 | let reasonValue = notification.userInfo![AVAudioSessionRouteChangeReasonKey].flatMap { 400 | AVAudioSession.RouteChangeReason(rawValue: $0 as! UInt) 401 | } 402 | let routeDescription = notification.userInfo![AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription 403 | 404 | NSLog("Route change:") 405 | switch (reasonValue) { 406 | case AVAudioSession.RouteChangeReason.newDeviceAvailable?: 407 | NSLog(" NewDeviceAvailable") 408 | case AVAudioSession.RouteChangeReason.oldDeviceUnavailable?: 409 | NSLog(" OldDeviceUnavailable") 410 | case AVAudioSession.RouteChangeReason.categoryChange?: 411 | NSLog(" CategoryChange") 412 | NSLog(" New Category: %@", AVAudioSession.sharedInstance().category.rawValue) 413 | case AVAudioSession.RouteChangeReason.override?: 414 | NSLog(" Override") 415 | case AVAudioSession.RouteChangeReason.wakeFromSleep?: 416 | NSLog(" WakeFromSleep") 417 | case AVAudioSession.RouteChangeReason.noSuitableRouteForCategory?: 418 | NSLog(" NoSuitableRouteForCategory") 419 | default: 420 | NSLog(" ReasonUnknown") 421 | } 422 | 423 | NSLog("Previous route:\n") 424 | NSLog("\(routeDescription?.description ?? "nil")") 425 | } 426 | 427 | @objc private func handleMediaServicesReset(_ notification: NSNotification) { 428 | // if we've received this notification, the media server has been reset 429 | // re-wire all the connections and start the engine 430 | NSLog("Media services have been reset!"); 431 | NSLog("Re-wiring connections and starting once again"); 432 | 433 | self.initAVAudioSession() 434 | self.createEngineAndAttachNodes() 435 | self.makeEngineConnections() 436 | self.startEngine() 437 | 438 | //notify the delegate 439 | self.delegate?.engineConfigurationHasChanged?() 440 | } 441 | 442 | private func createEngineAndAttachNodes() { 443 | _engine = AVAudioEngine() 444 | 445 | _engine.attach(_environment) 446 | _engine.attach(_launchSoundPlayer) 447 | 448 | for collisionPlayer in _collisionPlayerArray { 449 | _engine.attach(collisionPlayer) 450 | } 451 | 452 | } 453 | 454 | #endif 455 | 456 | 457 | } 458 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | GameView 7 | */ 8 | 9 | @import SceneKit; 10 | 11 | @class AudioEngine; 12 | 13 | @interface GameView : SCNView 14 | 15 | @property (strong) AudioEngine *gameAudioEngine; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | GameView 7 | */ 8 | 9 | #import "GameView.h" 10 | #import "AudioEngine.h" 11 | 12 | @interface GameView() 13 | 14 | @property (readwrite) CGPoint previousTouch; 15 | 16 | @end 17 | 18 | @implementation GameView 19 | 20 | 21 | - (void)awakeFromNib 22 | { 23 | [super awakeFromNib]; 24 | 25 | #if TARGET_OS_IOS || TARGET_OS_TV 26 | [self addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)]]; 27 | #endif 28 | } 29 | 30 | - (CGFloat)degreesFromRad:(CGFloat)rad 31 | { 32 | return (rad/M_PI) *180; 33 | } 34 | 35 | - (CGFloat)radFromDegrees:(CGFloat)degree 36 | { 37 | return (degree/180) *M_PI; 38 | } 39 | 40 | -(void)updateEulerAnglesAndListenerFromDeltaX:(CGFloat)dx DeltaY:(CGFloat)dy 41 | { 42 | //estimate the position deltas as the angular change and convert it to radians for scene kit 43 | float dYaw = [self radFromDegrees:dx]; 44 | float dPitch = [self radFromDegrees:dy]; 45 | 46 | //scale the feedback to make the transitions smooth and natural 47 | float scalar = 0.1; 48 | 49 | [self.pointOfView setEulerAngles:SCNVector3Make(self.pointOfView.eulerAngles.x+dPitch*scalar, 50 | self.pointOfView.eulerAngles.y+dYaw*scalar, 51 | self.pointOfView.eulerAngles.z)]; 52 | 53 | 54 | SCNNode *listener = [self.scene.rootNode childNodeWithName:@"listenerLight" recursively:YES]; 55 | [listener setEulerAngles:SCNVector3Make(self.pointOfView.eulerAngles.x, 56 | self.pointOfView.eulerAngles.y, 57 | self.pointOfView.eulerAngles.z)]; 58 | 59 | 60 | //convert the scene kit angular orientation (radians) to degrees for AVAudioEngine and match the orientation 61 | [self.gameAudioEngine 62 | updateListenerOrientation:AVAudioMake3DAngularOrientation([self degreesFromRad:-1*self.pointOfView.eulerAngles.y], 63 | [self degreesFromRad:-1*self.pointOfView.eulerAngles.x], 64 | [self degreesFromRad:self.pointOfView.eulerAngles.z])]; 65 | } 66 | 67 | #if TARGET_OS_IOS || TARGET_OS_TV 68 | 69 | - (void)panGesture:(UIPanGestureRecognizer *)panRecognizer 70 | { 71 | //capture the first touch 72 | if(panRecognizer.state == UIGestureRecognizerStateBegan) 73 | self.previousTouch = [panRecognizer locationInView:self]; 74 | 75 | CGPoint currentTouch = [panRecognizer locationInView:self]; 76 | 77 | //Calculate the change in position 78 | float dX = currentTouch.x-self.previousTouch.x; 79 | float dY = currentTouch.y-self.self.previousTouch.y; 80 | 81 | self.previousTouch = currentTouch; 82 | 83 | [self updateEulerAnglesAndListenerFromDeltaX:dX DeltaY:dY]; 84 | } 85 | 86 | #else 87 | -(void)mouseDown:(NSEvent *)theEvent 88 | { 89 | /* Called when a mouse click occurs */ 90 | [super mouseDown:theEvent]; 91 | } 92 | 93 | - (void)mouseDragged:(NSEvent *)theEvent 94 | { 95 | /* Called when a mouse dragged occurs */ 96 | [super mouseDragged:theEvent]; 97 | 98 | [self updateEulerAnglesAndListenerFromDeltaX:theEvent.deltaX DeltaY:theEvent.deltaY]; 99 | 100 | } 101 | 102 | - (void)magnifyWithEvent:(NSEvent *)event 103 | { 104 | //implement this method to zoom in and out 105 | //[super magnifyWithEvent:event]; 106 | } 107 | 108 | - (void)rotateWithEvent:(NSEvent *)event 109 | { 110 | //implement this to have to listener roll along the perpendicular axis to the screen plane 111 | //[super rotateWithEvent:event]; 112 | } 113 | 114 | #endif //TARGET_OS_IOS || TARGET_OS_TV 115 | 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameView.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2015/4/20. 6 | // 7 | /* 8 | Copyright (C) 2015 Apple Inc. All Rights Reserved. 9 | See LICENSE.txt for this sample’s licensing information 10 | 11 | Abstract: 12 | GameView 13 | */ 14 | 15 | import SceneKit 16 | import AVFoundation 17 | 18 | @objc(GameView) 19 | class GameView: SCNView { 20 | 21 | var gameAudioEngine: AudioEngine! 22 | 23 | var previousTouch: CGPoint = CGPoint() 24 | 25 | override func awakeFromNib() { 26 | super.awakeFromNib() 27 | 28 | #if os(iOS) || os(tvOS) 29 | self.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panGesture))) 30 | #endif 31 | } 32 | 33 | func degreesFromRad(_ rad: F) -> F { 34 | return (rad / .pi) * 180 35 | } 36 | 37 | func radFromDegrees(_ degree: F) -> F { 38 | return (degree/180) * .pi 39 | } 40 | 41 | private func updateEulerAnglesAndListener(fromDeltaX dx: CGFloat, deltaY dy: CGFloat) { 42 | //estimate the position deltas as the angular change and convert it to radians for scene kit 43 | let dYaw = self.radFromDegrees(SCNVectorFloat(dx)) 44 | let dPitch = self.radFromDegrees(SCNVectorFloat(dy)) 45 | 46 | //scale the feedback to make the transitions smooth and natural 47 | let scalar: SCNVectorFloat = 0.1 48 | 49 | self.pointOfView?.eulerAngles = SCNVector3Make(self.pointOfView!.eulerAngles.x+dPitch*scalar, 50 | self.pointOfView!.eulerAngles.y+dYaw*scalar, 51 | self.pointOfView!.eulerAngles.z) 52 | 53 | 54 | let listener = self.scene!.rootNode.childNode(withName: "listenerLight", recursively: true) 55 | listener?.eulerAngles = SCNVector3Make(self.pointOfView!.eulerAngles.x, 56 | self.pointOfView!.eulerAngles.y, 57 | self.pointOfView!.eulerAngles.z) 58 | 59 | 60 | //convert the scene kit angular orientation (radians) to degrees for AVAudioEngine and match the orientation 61 | self.gameAudioEngine 62 | .updateListenerOrientation(AVAudioMake3DAngularOrientation(Float(self.degreesFromRad(-1*self.pointOfView!.eulerAngles.y)), 63 | Float(self.degreesFromRad(-1*self.pointOfView!.eulerAngles.x)), 64 | Float(self.degreesFromRad(self.pointOfView!.eulerAngles.z)))) 65 | } 66 | 67 | #if os(iOS) || os(tvOS) 68 | 69 | @objc private func panGesture(_ panRecognizer: UIPanGestureRecognizer) { 70 | //capture the first touch 71 | if panRecognizer.state == .began { 72 | self.previousTouch = panRecognizer.location(in: self) 73 | } 74 | 75 | let currentTouch = panRecognizer.location(in: self) 76 | 77 | //Calculate the change in position 78 | let dX = currentTouch.x-self.previousTouch.x 79 | let dY = currentTouch.y-self.self.previousTouch.y 80 | 81 | self.previousTouch = currentTouch 82 | 83 | self.updateEulerAnglesAndListener(fromDeltaX: dX, deltaY: dY) 84 | } 85 | 86 | #else 87 | override func mouseDown(with theEvent: NSEvent) { 88 | /* Called when a mouse click occurs */ 89 | super.mouseDown(with: theEvent) 90 | } 91 | 92 | override func mouseDragged(with theEvent: NSEvent) { 93 | /* Called when a mouse dragged occurs */ 94 | super.mouseDragged(with: theEvent) 95 | 96 | self.updateEulerAnglesAndListener(fromDeltaX: theEvent.deltaX, deltaY: theEvent.deltaY) 97 | 98 | } 99 | 100 | override func magnify(with event: NSEvent) { 101 | //implement this method to zoom in and out 102 | //super.magnify(with: event) 103 | } 104 | 105 | override func rotate(with event: NSEvent) { 106 | //implement this to have to listener roll along the perpendicular axis to the screen plane 107 | //super.rotate(with: event) 108 | } 109 | 110 | #endif //os(iOS) || os(TvOS) 111 | 112 | 113 | } 114 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | GameViewController 7 | */ 8 | 9 | @import SceneKit; 10 | 11 | #if TARGET_OS_IOS || TARGET_OS_TV 12 | @interface GameViewController : UIViewController 13 | #else 14 | @interface GameViewController : NSViewController 15 | #endif 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | GameViewController 7 | */ 8 | 9 | #import "AudioEngine.h" 10 | 11 | #import "GameView.h" 12 | #import "GameViewController.h" 13 | 14 | @interface GameViewController() { 15 | AudioEngine *_audioEngine; 16 | } 17 | 18 | @property (assign) GameView *gameView; 19 | 20 | @end 21 | 22 | @implementation GameViewController 23 | 24 | static float randFloat(float min, float max){ 25 | return min + ((max-min)*(rand()/(float)RAND_MAX)); 26 | } 27 | 28 | - (void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact 29 | { 30 | if (contact.collisionImpulse > 0.6 /* arbitrary threshold */) { 31 | AVAudio3DPoint contactPoint = AVAudioMake3DPoint(contact.contactPoint.x, contact.contactPoint.y, contact.contactPoint.z); 32 | [_audioEngine playCollisionSoundForSCNNode:contact.nodeB position:contactPoint impulse:contact.collisionImpulse]; 33 | } 34 | } 35 | 36 | - (void)setupPhysicsScene:(SCNScene *)scene 37 | { 38 | SCNNode *cube = [scene.rootNode childNodeWithName:@"Cube" recursively:YES]; 39 | cube.castsShadow = NO; 40 | 41 | SCNNode *lightNode = [scene.rootNode childNodeWithName:@"MainLight" recursively:YES]; 42 | lightNode.light.shadowMode = SCNShadowModeModulated; 43 | 44 | SCNVector3 min, max; 45 | [cube getBoundingBoxMin:&min max:&max]; 46 | 47 | float cubeSize = (max.y-min.y) * cube.scale.y; 48 | float wallWidth = 1; 49 | SCNBox *wallGeometry = [SCNBox boxWithWidth:cubeSize height:cubeSize length:wallWidth chamferRadius:0]; 50 | wallGeometry.firstMaterial.transparency = 0; 51 | 52 | float wallPosition = (cubeSize/2 + wallWidth/2); 53 | 54 | SCNNode *wall1 = [SCNNode node]; 55 | wall1.name = @"Wall"; 56 | wall1.geometry = wallGeometry; 57 | wall1.physicsBody = [SCNPhysicsBody staticBody]; 58 | wall1.physicsBody.contactTestBitMask = SCNPhysicsCollisionCategoryDefault; 59 | wall1.position = SCNVector3Make(0, 0, -wallPosition); 60 | [scene.rootNode addChildNode:wall1]; 61 | 62 | SCNNode *wall2 = [wall1 copy]; 63 | wall2.position = SCNVector3Make(0, 0, wallPosition); 64 | wall2.eulerAngles = SCNVector3Make(M_PI, 0, 0); 65 | [scene.rootNode addChildNode:wall2]; 66 | 67 | SCNNode *wall3 = [wall1 copy]; 68 | wall3.position = SCNVector3Make(-wallPosition, 0, 0); 69 | wall3.eulerAngles = SCNVector3Make(0, M_PI_2, 0); 70 | [scene.rootNode addChildNode:wall3]; 71 | 72 | SCNNode *wall4 = [wall1 copy]; 73 | wall4.position = SCNVector3Make(wallPosition, 0, 0); 74 | wall4.eulerAngles = SCNVector3Make(0, -M_PI_2, 0); 75 | [scene.rootNode addChildNode:wall4]; 76 | 77 | SCNNode *wall5 = [wall1 copy]; 78 | wall5.position = SCNVector3Make(0, wallPosition, 0); 79 | wall5.eulerAngles = SCNVector3Make(M_PI_2, 0, 0); 80 | [scene.rootNode addChildNode:wall5]; 81 | 82 | SCNNode *wall6 = [wall1 copy]; 83 | wall6.position = SCNVector3Make(0, -wallPosition, 0); 84 | wall6.eulerAngles = SCNVector3Make(-M_PI_2, 0, 0); 85 | [scene.rootNode addChildNode:wall6]; 86 | 87 | SCNNode *pointOfViewCamera = [scene.rootNode childNodeWithName:@"Camera" recursively:YES]; 88 | self.gameView.pointOfView = pointOfViewCamera; 89 | 90 | SCNNode *listener = [scene.rootNode childNodeWithName:@"listenerLight" recursively:YES]; 91 | listener.position = pointOfViewCamera.position; 92 | 93 | // setup physics callbacks 94 | scene.physicsWorld.contactDelegate = self; 95 | 96 | // turn off gravity for more fun 97 | //scene.physicsWorld.gravity = SCNVector3Zero; 98 | } 99 | 100 | - (void)createAndLaunchBall:(NSString*)ballID 101 | { 102 | [SCNTransaction begin]; 103 | 104 | SCNNode *ball = [SCNNode node]; 105 | ball.name = ballID; 106 | ball.geometry = [SCNSphere sphereWithRadius:0.2]; 107 | ball.geometry.firstMaterial.diffuse.contents = @"assets.scnassets/texture.jpg"; 108 | ball.geometry.firstMaterial.reflective.contents = @"assets.scnassets/envmap.jpg"; 109 | 110 | ball.position = SCNVector3Make(0, -2, 2.5); 111 | 112 | ball.physicsBody = [SCNPhysicsBody dynamicBody]; 113 | ball.physicsBody.restitution = 1.2; //bounce! 114 | 115 | // create an AVAudioEngine player which will be tied to this ball 116 | [_audioEngine createPlayerForSCNNode:ball]; 117 | 118 | [self.gameView.scene.rootNode addChildNode:ball]; 119 | 120 | // bias the direction towards one of the side walls 121 | float whichWall = roundf(randFloat(0, 1)); // 0 is left and 1 is right 122 | float xVal = (1 - whichWall) * randFloat(-8, -3) + whichWall * randFloat(3, 8); 123 | 124 | // initial force 125 | [ball.physicsBody applyForce:SCNVector3Make(xVal, randFloat(0,5), -randFloat(5,15)) atPosition:SCNVector3Zero impulse:YES]; 126 | [ball.physicsBody applyTorque:SCNVector4Make(randFloat(-1,1), randFloat(-1,1), randFloat(-1,1), randFloat(-1,1)) impulse:YES]; 127 | 128 | [SCNTransaction commit]; 129 | } 130 | 131 | - (void)removeBall:(SCNNode *)ball 132 | { 133 | [_audioEngine destroyPlayerForSCNNode:ball]; 134 | [ball removeFromParentNode]; 135 | } 136 | 137 | -(void)viewDidLoad 138 | { 139 | [super viewDidLoad]; 140 | 141 | // create a new scene 142 | SCNScene *scene = [SCNScene sceneNamed:@"cube.scn" inDirectory:@"assets.scnassets" options:nil]; 143 | 144 | // find the SCNView 145 | for (id view in self.view.subviews) { 146 | if ([[view class] isSubclassOfClass:[SCNView class]]) { 147 | self.gameView = view; 148 | } 149 | } 150 | 151 | // set the scene to the view 152 | self.gameView.scene = scene; 153 | 154 | // setup the room 155 | [self setupPhysicsScene:scene]; 156 | 157 | // setup audio engine 158 | _audioEngine = [[AudioEngine alloc] init]; 159 | 160 | //make the listener position the same as the camera point of view 161 | [_audioEngine updateListenerPosition:AVAudioMake3DPoint(0, -2, 2.5)]; 162 | 163 | self.gameView.gameAudioEngine = _audioEngine; 164 | 165 | // create a queue that will handle adding SceneKit nodes (balls) and corresponding AVAudioEngine players 166 | dispatch_queue_t queue = dispatch_queue_create("DemBalls", DISPATCH_QUEUE_SERIAL); 167 | dispatch_async(queue, ^{ 168 | while (1) { 169 | while (_audioEngine.isRunning) { 170 | static int ballIndex = 0; 171 | 172 | // play the launch sound 173 | [_audioEngine playLaunchSoundAtPosition:AVAudioMake3DPoint(0, -2, 2.5) completionHandler:^{ 174 | 175 | // launch sound has finished scheduling 176 | // now create and launch a ball 177 | NSString *ballID = [[NSNumber numberWithInt:ballIndex] stringValue]; 178 | [self createAndLaunchBall:ballID]; 179 | ++ballIndex; 180 | }]; 181 | 182 | // wait for some time before launching the next ball 183 | sleep(4); 184 | } 185 | } 186 | }); 187 | 188 | // configure the view 189 | #if TARGET_OS_IOS ||TARGET_OS_TV 190 | self.gameView.backgroundColor = [UIColor blackColor]; 191 | #else 192 | self.gameView.backgroundColor = [NSColor blackColor]; 193 | #endif 194 | } 195 | 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /AVAEGamingExample/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2015/4/20. 6 | // 7 | /* 8 | Copyright (C) 2015 Apple Inc. All Rights Reserved. 9 | See LICENSE.txt for this sample’s licensing information 10 | 11 | Abstract: 12 | GameViewController 13 | */ 14 | 15 | import Foundation 16 | import AVFoundation 17 | import SceneKit 18 | 19 | #if os(iOS) || os(tvOS) 20 | typealias OSViewController = UIViewController 21 | typealias SCNVectorFloat = Float 22 | typealias OSColor = UIColor 23 | #else 24 | typealias OSViewController = NSViewController 25 | typealias SCNVectorFloat = CGFloat 26 | typealias OSColor = NSColor 27 | #endif 28 | @objc(GameViewController) 29 | class GameViewController: OSViewController, SCNPhysicsContactDelegate, AudioEngineDelegate { 30 | 31 | var _audioEngine: AudioEngine! 32 | 33 | private var gameView: GameView! 34 | 35 | func randFloat(_ min: F, _ max: F) -> F { 36 | return min + ((max-min)*(F(arc4random())/F(RAND_MAX))) 37 | } 38 | 39 | let BallCategoryBit = Int(SCNPhysicsCollisionCategory.default.rawValue) 40 | let WallCategoryBit = Int(SCNPhysicsCollisionCategory.static.rawValue) 41 | 42 | func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) { 43 | if contact.collisionImpulse > 0.6 /* arbitrary threshold */ { 44 | 45 | let contactPoint = AVAudioMake3DPoint(Float(contact.contactPoint.x), Float(contact.contactPoint.y), Float(contact.contactPoint.z)) 46 | _audioEngine.playCollisionSoundForSCNNode(contact.nodeB, position: contactPoint, impulse: Float(contact.collisionImpulse)) 47 | } 48 | } 49 | 50 | func setupPhysicsScene(_ scene: SCNScene) { 51 | let cube = scene.rootNode.childNode(withName: "Cube", recursively: true)! 52 | cube.castsShadow = false 53 | 54 | let lightNode = scene.rootNode.childNode(withName: "MainLight", recursively: true)! 55 | lightNode.light!.shadowMode = SCNShadowMode.modulated 56 | 57 | let (min, max) = cube.boundingBox 58 | 59 | let cubeSize: SCNVectorFloat = (max.y-min.y) * cube.scale.y 60 | let wallWidth: SCNVectorFloat = 1 61 | let wallGeometry = SCNBox(width: CGFloat(cubeSize), height: CGFloat(cubeSize), length: CGFloat(wallWidth), chamferRadius: 0) 62 | wallGeometry.firstMaterial!.transparency = 0 63 | 64 | let wallPosition = (cubeSize/2 + wallWidth/2) 65 | 66 | let wall1 = SCNNode() 67 | wall1.name = "Wall" 68 | wall1.geometry = wallGeometry 69 | wall1.physicsBody = SCNPhysicsBody.static() 70 | if #available(OSX 10.11, iOS 9.0, *) { 71 | wall1.physicsBody?.contactTestBitMask = Int(SCNPhysicsCollisionCategory.default.rawValue) 72 | } 73 | wall1.position = SCNVector3Make(0, 0, -wallPosition) 74 | scene.rootNode.addChildNode(wall1) 75 | 76 | let wall2 = wall1.copy() as! SCNNode 77 | wall2.position = SCNVector3Make(0, 0, wallPosition) 78 | wall2.eulerAngles = SCNVector3Make(.pi, 0, 0) 79 | scene.rootNode.addChildNode(wall2) 80 | 81 | let wall3 = wall1.copy() as! SCNNode 82 | wall3.position = SCNVector3Make(-wallPosition, 0, 0) 83 | wall3.eulerAngles = SCNVector3Make(0, .pi/2, 0) 84 | scene.rootNode.addChildNode(wall3) 85 | 86 | let wall4 = wall1.copy() as! SCNNode 87 | wall4.position = SCNVector3Make(wallPosition, 0, 0) 88 | wall4.eulerAngles = SCNVector3Make(0, -.pi/2, 0) 89 | scene.rootNode.addChildNode(wall4) 90 | 91 | let wall5 = wall1.copy() as! SCNNode 92 | wall5.position = SCNVector3Make(0, wallPosition, 0) 93 | wall5.eulerAngles = SCNVector3Make(.pi/2, 0, 0) 94 | scene.rootNode.addChildNode(wall5) 95 | 96 | let wall6 = wall1.copy() as! SCNNode 97 | wall6.position = SCNVector3Make(0, -wallPosition, 0) 98 | wall6.eulerAngles = SCNVector3Make(-.pi/2, 0, 0) 99 | scene.rootNode.addChildNode(wall6) 100 | 101 | let pointOfViewCamera = scene.rootNode.childNode(withName: "Camera", recursively: true)! 102 | self.gameView.pointOfView = pointOfViewCamera 103 | 104 | let listener = scene.rootNode.childNode(withName: "listenerLight", recursively: true)! 105 | listener.position = pointOfViewCamera.position 106 | 107 | // setup physics callbacks 108 | scene.physicsWorld.contactDelegate = self 109 | 110 | // turn off gravity for more fun 111 | // scene.physicsWorld.gravity = SCNVector3Zero 112 | } 113 | 114 | private func createAndLaunchBall(_ ballID: String) { 115 | SCNTransaction.begin() 116 | 117 | let ball = SCNNode() 118 | ball.name = ballID 119 | ball.geometry = SCNSphere(radius: 0.2) 120 | ball.geometry!.firstMaterial!.diffuse.contents = "assets.scnassets/texture.jpg" 121 | ball.geometry!.firstMaterial!.reflective.contents = "assets.scnassets/envmap.jpg" 122 | 123 | ball.position = SCNVector3Make(0, -2, 2.5) 124 | 125 | ball.physicsBody = SCNPhysicsBody.dynamic() 126 | ball.physicsBody!.restitution = 1.2 //bounce! 127 | if #available(OSX 10.11, *) { 128 | ball.physicsBody?.contactTestBitMask = BallCategoryBit | WallCategoryBit 129 | } 130 | 131 | // create an AVAudioEngine player which will be tied to this ball 132 | _audioEngine.createPlayerForSCNNode(ball) 133 | 134 | self.gameView.scene!.rootNode.addChildNode(ball) 135 | 136 | // bias the direction towards one of the side walls 137 | let whichWall = round(randFloat(0 as SCNVectorFloat, 1)); // 0 is left and 1 is right 138 | let xVal = (1 - whichWall) * randFloat(-8, -3) + whichWall * randFloat(3, 8) 139 | 140 | // initial force 141 | ball.physicsBody!.applyForce(SCNVector3Make(xVal, randFloat(0,5), -randFloat(5,15)), at: SCNVector3Zero, asImpulse: true) 142 | ball.physicsBody!.applyTorque(SCNVector4Make(randFloat(-1,1), randFloat(-1,1), randFloat(-1,1), randFloat(-1,1)), asImpulse: true) 143 | 144 | SCNTransaction.commit() 145 | } 146 | 147 | func removeBall(_ ball: SCNNode) { 148 | _audioEngine.destroyPlayerForSCNNode(ball) 149 | ball.removeFromParentNode() 150 | } 151 | 152 | override func viewDidLoad() { 153 | super.viewDidLoad() 154 | 155 | // create a new scene 156 | let options: [SCNSceneSource.LoadingOption : Any]? = nil //###Needed to build with Xcode 8 beta 6 157 | let scene = SCNScene(named: "cube.scn", inDirectory: "assets.scnassets", options: options)! 158 | 159 | // find the SCNView 160 | for view in self.view.subviews { 161 | if let view = view as? GameView { 162 | self.gameView = view 163 | } 164 | } 165 | 166 | // set the scene to the view 167 | self.gameView.scene = scene 168 | 169 | // setup the room 170 | self.setupPhysicsScene(scene) 171 | 172 | // setup audio engine 173 | _audioEngine = AudioEngine() 174 | 175 | //make the listener position the same as the camera point of view 176 | _audioEngine.updateListenerPosition(AVAudioMake3DPoint(0, -2, 2.5)) 177 | 178 | self.gameView.gameAudioEngine = _audioEngine; 179 | 180 | // create a queue that will handle adding SceneKit nodes (balls) and corresponding AVAudioEngine players 181 | let queue = DispatchQueue(label: "DemBalls", attributes: []/*DispatchQueue.Attributes.serial*/) 182 | queue.async { 183 | while true { 184 | struct Static { 185 | static var ballIndex = 0 186 | } 187 | while self._audioEngine.isRunning { 188 | 189 | // play the launch sound 190 | self._audioEngine.playLaunchSoundAtPosition(AVAudioMake3DPoint(0, -2, 2.5)) { 191 | 192 | // launch sound has finished scheduling 193 | // now create and launch a ball 194 | let ballID = String(Static.ballIndex) 195 | self.createAndLaunchBall(ballID) 196 | Static.ballIndex += 1 197 | } 198 | 199 | // wait for some time before launching the next ball 200 | sleep(4); 201 | } 202 | } 203 | } 204 | 205 | // configure the view 206 | self.gameView.backgroundColor = .black 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /AVAEGamingExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AVAEGamingExample/Images.xcassets/texture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "texture.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "idiom" : "universal", 17 | "scale" : "3x" 18 | } 19 | ], 20 | "info" : { 21 | "version" : 1, 22 | "author" : "xcode" 23 | } 24 | } -------------------------------------------------------------------------------- /AVAEGamingExample/Images.xcassets/texture.imageset/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/Images.xcassets/texture.imageset/texture.png -------------------------------------------------------------------------------- /AVAEGamingExample/assets.scnassets/cube.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/assets.scnassets/cube.scn -------------------------------------------------------------------------------- /AVAEGamingExample/assets.scnassets/envmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/assets.scnassets/envmap.jpg -------------------------------------------------------------------------------- /AVAEGamingExample/assets.scnassets/texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/assets.scnassets/texture.jpg -------------------------------------------------------------------------------- /AVAEGamingExample/assets.scnassets/wall2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/assets.scnassets/wall2.png -------------------------------------------------------------------------------- /AVAEGamingExample/bounce.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/bounce.caf -------------------------------------------------------------------------------- /AVAEGamingExample/launchSound.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/AVAEGamingExample-Swift/8c7d8b1c9ef324518b9d12c5586e383216730790/AVAEGamingExample/launchSound.caf -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Sample code project: AVAudioEngine 3D Audio Example 2 | Version: 2.0 3 | 4 | IMPORTANT: This Apple software is supplied to you by Apple 5 | Inc. ("Apple") in consideration of your agreement to the following 6 | terms, and your use, installation, modification or redistribution of 7 | this Apple software constitutes acceptance of these terms. If you do 8 | not agree with these terms, please do not use, install, modify or 9 | redistribute this Apple software. 10 | 11 | In consideration of your agreement to abide by the following terms, and 12 | subject to these terms, Apple grants you a personal, non-exclusive 13 | license, under Apple's copyrights in this original Apple software (the 14 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 15 | Software, with or without modifications, in source and/or binary forms; 16 | provided that if you redistribute the Apple Software in its entirety and 17 | without modifications, you must retain this notice and the following 18 | text and disclaimers in all such redistributions of the Apple Software. 19 | Neither the name, trademarks, service marks or logos of Apple Inc. may 20 | be used to endorse or promote products derived from the Apple Software 21 | without specific prior written permission from Apple. Except as 22 | expressly stated in this notice, no other rights or licenses, express or 23 | implied, are granted by Apple herein, including but not limited to any 24 | patent rights that may be infringed by your derivative works or by other 25 | works in which the Apple Software may be incorporated. 26 | 27 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 28 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 29 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 30 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 31 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 32 | 33 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 34 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 37 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 38 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 39 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 40 | POSSIBILITY OF SUCH DAMAGE. 41 | 42 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AVAudioEngine Gaming Example 2 | 3 | This sample demonstrate the use of the AVAudioEngine, AVAudioEnvironmentNode and AVAudioPlayerNode to play positional multichannel audio using SceneKit to setup a cube environment and manage some bouncing balls. When the balls hit and bounce off a wall, positional audio is played using AVAudioEngine. 4 | 5 | ## Requirements 6 | 7 | Xcode 8.1 or greater 8 | 9 | ### Build 10 | 11 | iOS 9.0 SDK or greater 12 | tvOS 9.0 SDK or greater 13 | macOS 10.11 SDK or greater 14 | 15 | ### Runtime 16 | 17 | iOS 9.0 or greater 18 | tvOS 9.0 or greater 19 | macOS 10.12 or greater 20 | 21 | Copyright (C) 2015-2016 Apple Inc. All rights reserved. 22 | -------------------------------------------------------------------------------- /README2.md: -------------------------------------------------------------------------------- 1 | # AVAEGamingExample -- AVAudioEngine 3D Audio Example 2 | 3 | Translated by OOPer in cooperation with shlab.jp, on 2015/4/20. 4 | 5 | Based on 6 | 7 | 2016-11-03. 8 | 9 | As this is a line-by-line translation from the original sample code, "redistribute the Apple Software in its entirety and without modifications" would apply. See LICENSE.txt . 10 | Some faults caused by my translation may exist. Not all features tested. 11 | You should not contact to Apple or SHLab(jp) about any faults caused by my translation. 12 | 13 | ## Requirements 14 | 15 | ### Build 16 | 17 | Xcode 10.2 18 | -------------------------------------------------------------------------------- /iOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | @import UIKit; 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /iOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2016/12/13. 6 | // Copyright © 2016 apple. All rights reserved. 7 | // 8 | /* 9 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | Application Delegate 14 | */ 15 | 16 | import UIKit 17 | 18 | @UIApplicationMain 19 | class AppDelegate: UIResponder, UIApplicationDelegate { 20 | 21 | var window: UIWindow? 22 | 23 | 24 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 25 | // Override point for customization after application launch. 26 | return true 27 | } 28 | 29 | func applicationWillResignActive(_ application: UIApplication) { 30 | // 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. 31 | // 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. 32 | } 33 | 34 | func applicationDidEnterBackground(_ application: UIApplication) { 35 | // 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. 36 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 37 | } 38 | 39 | func applicationWillEnterForeground(_ application: UIApplication) { 40 | // 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. 41 | } 42 | 43 | func applicationDidBecomeActive(_ application: UIApplication) { 44 | // 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. 45 | } 46 | 47 | func applicationWillTerminate(_ application: UIApplication) { 48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /iOS/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /iOS/Base.lproj/iOSMain.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 | -------------------------------------------------------------------------------- /iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | iOSMain 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /iOS/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | 8 | @import UIKit; 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /macOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | @import Cocoa; 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /macOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 14 | { 15 | // Insert code here to initialize your application 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /macOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2015/4/20. 6 | // 7 | /* 8 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 9 | See LICENSE.txt for this sample’s licensing information 10 | 11 | Abstract: 12 | Application Delegate 13 | */ 14 | 15 | import Cocoa 16 | 17 | @NSApplicationMain 18 | @objc(AppDelegate) 19 | class AppDelegate: NSObject, NSApplicationDelegate { 20 | 21 | func applicationDidFinishLaunching(_ aNotification: Notification) { 22 | // Insert code here to initialize your application 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 2.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2014 apple. All rights reserved. 29 | NSMainStoryboardFile 30 | macOSMain 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /macOS/macOSMain.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | Default 512 | 513 | 514 | 515 | 516 | 517 | 518 | Left to Right 519 | 520 | 521 | 522 | 523 | 524 | 525 | Right to Left 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | Default 537 | 538 | 539 | 540 | 541 | 542 | 543 | Left to Right 544 | 545 | 546 | 547 | 548 | 549 | 550 | Right to Left 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | -------------------------------------------------------------------------------- /macOS/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | @import Cocoa; 8 | 9 | int main(int argc, const char * argv[]) { 10 | return NSApplicationMain(argc, argv); 11 | } 12 | -------------------------------------------------------------------------------- /tvOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | @import UIKit; 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /tvOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Application Delegate 7 | */ 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /tvOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AVAEGamingExample 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2016/12/13. 6 | // Copyright © 2016 apple. All rights reserved. 7 | // 8 | /* 9 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | Application Delegate 14 | */ 15 | 16 | import UIKit 17 | 18 | @UIApplicationMain 19 | class AppDelegate: UIResponder, UIApplicationDelegate { 20 | 21 | var window: UIWindow? 22 | 23 | 24 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 25 | // Override point for customization after application launch. 26 | return true 27 | } 28 | 29 | func applicationWillResignActive(_ application: UIApplication) { 30 | // 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. 31 | // 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. 32 | } 33 | 34 | func applicationDidEnterBackground(_ application: UIApplication) { 35 | // 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. 36 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 37 | } 38 | 39 | func applicationWillEnterForeground(_ application: UIApplication) { 40 | // 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. 41 | } 42 | 43 | func applicationDidBecomeActive(_ application: UIApplication) { 44 | // 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. 45 | } 46 | 47 | func applicationWillTerminate(_ application: UIApplication) { 48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /tvOS/Base.lproj/tvOSMain.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 | -------------------------------------------------------------------------------- /tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIcons 10 | 11 | CFBundleIcons~ipad 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 2.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1 27 | LSRequiresIPhoneOS 28 | 29 | UIMainStoryboardFile 30 | tvOSMain 31 | UIRequiredDeviceCapabilities 32 | 33 | arm64 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /tvOS/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | 8 | @import UIKit; 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------