├── .gitignore ├── Common └── Organ.wav ├── LICENSE ├── README.md ├── iOS ├── .swiftlint.yml ├── AudioUnitManager.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── AudioUnitManager.xcscheme └── AudioUnitManager │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── AudioUnitGenericView.swift │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Default-568h@2x.png │ ├── DropDown │ ├── .github │ │ └── contributing.md │ ├── .gitignore │ ├── .swift-version │ ├── DropDown.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── DropDown.xcscheme │ ├── DropDown │ │ ├── DropDown.h │ │ ├── Info.plist │ │ ├── helpers │ │ │ ├── DPDConstants.swift │ │ │ ├── DPDKeyboardListener.swift │ │ │ └── DPDUIView+Extension.swift │ │ ├── resources │ │ │ └── DropDownCell.xib │ │ └── src │ │ │ ├── DropDown+Appearance.swift │ │ │ ├── DropDown.swift │ │ │ └── DropDownCell.swift │ └── Info.plist │ ├── Info.plist │ └── ViewController.swift └── macOS ├── .swiftlint.yml ├── AudioUnitManager.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── swiftpm │ └── Package.resolved └── AudioUnitManager ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ ├── AudioUnitIcon-1024.png │ ├── AudioUnitIcon-128.png │ ├── AudioUnitIcon-16.png │ ├── AudioUnitIcon-256.png │ ├── AudioUnitIcon-32.png │ ├── AudioUnitIcon-512.png │ ├── AudioUnitIcon-64.png │ └── Contents.json ├── Contents.json └── Faded Red.colorset │ └── Contents.json ├── AudioUnitGenericView.swift ├── AudioUnitGenericWindow.swift ├── AudioUnitGenericWindow.xib ├── AudioUnitManager+Effects.swift ├── AudioUnitManager+MIDI.swift ├── AudioUnitManager+Player.swift ├── AudioUnitManager.swift ├── AudioUnitParamSlider.swift ├── AudioUnitToolbarController.swift ├── AudioUnitToolbarController.xib ├── Base.lproj └── Main.storyboard ├── ClosureMenuItem.swift ├── Extensions.swift ├── Info.plist ├── InstrumentPlayer.swift ├── MenuButton.swift └── WaveformView.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | 92 | .DS_Store -------------------------------------------------------------------------------- /Common/Organ.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/Common/Organ.wav -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 AudioKit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Audio Unit Manager 2 | 3 | Open source audio unit host app for use in testing your AudioUnits or building a host app from. 4 | 5 | # CAUTION: Not functional yet, use code from AudioKit v4 instead while this is being fixed up. 6 | 7 | -------------------------------------------------------------------------------- /iOS/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: # rule identifiers to exclude from running 2 | - file_header 3 | - attributes 4 | #- cyclomatic_complexity 5 | - type_name 6 | - todo 7 | 8 | 9 | type_body_length: 10 | - 800 # warning 11 | - 4000 # error 12 | 13 | function_body_length: 14 | - 400 # warning 15 | - 4000 # error 16 | 17 | line_length: 18 | - 120 # warning 19 | - 5000 # error 20 | 21 | file_length: 22 | - 1000 # warning 23 | - 10000 # error 24 | 25 | identifier_name: 26 | min_length: 27 | - 1 # warning 28 | 29 | force_cast: error 30 | force_unwrapping: error 31 | empty_count: error 32 | force_try: error 33 | for_where: error 34 | 35 | cyclomatic_complexity: 36 | - 10 # warning 37 | - 100 # error 38 | 39 | excluded: 40 | 41 | 42 | opt_in_rules: 43 | - legacy_constructor 44 | - closure_spacing 45 | - closure_end_indentation 46 | #- conditional_returns_on_newline 47 | - empty_count 48 | - explicit_init 49 | - first_where 50 | - nimble_operator 51 | #- number_separator 52 | - operator_usage_whitespace 53 | - overridden_super_call 54 | #- private_outlet 55 | - prohibited_super_call 56 | - redundant_nil_coalescing 57 | - switch_case_on_newline 58 | - file_length 59 | - weak_delegate 60 | - force_cast 61 | - object_literal 62 | - line_length 63 | - attributes 64 | - force_unwrapping 65 | - identifier_name 66 | - type_name 67 | - type_body_length 68 | - function_parameter_count 69 | - class_delegate_protocol 70 | - force_try -------------------------------------------------------------------------------- /iOS/AudioUnitManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B1698AE51F684755008F397D /* Organ.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4704C2E1F5D2B3C004C087E /* Organ.wav */; }; 11 | B1756EAB1F411D5A00792670 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1756EAA1F411D5A00792670 /* AppDelegate.swift */; }; 12 | B1756EAD1F411D5A00792670 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1756EAC1F411D5A00792670 /* ViewController.swift */; }; 13 | B1756EB01F411D5A00792670 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1756EAE1F411D5A00792670 /* Main.storyboard */; }; 14 | B1756EB21F411D5A00792670 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B1756EB11F411D5A00792670 /* Assets.xcassets */; }; 15 | B1756EB51F411D5A00792670 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1756EB31F411D5A00792670 /* LaunchScreen.storyboard */; }; 16 | B1756ECA1F41FD3A00792670 /* AudioUnitGenericView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1756EC91F41FD3A00792670 /* AudioUnitGenericView.swift */; }; 17 | C4067FE41F5D415C00FA09A4 /* DropDown.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4067FE31F5D411900FA09A4 /* DropDown.framework */; }; 18 | C4067FE51F5D415C00FA09A4 /* DropDown.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4067FE31F5D411900FA09A4 /* DropDown.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | C4704C3A1F5D2C15004C087E /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C4704C391F5D2C15004C087E /* Default-568h@2x.png */; }; 20 | EAF51AEB241723E7005E7000 /* AudioKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAF51AEA241723E7005E7000 /* AudioKit.xcframework */; }; 21 | EAF51B6B2417328D005E7000 /* AudioKitUI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAF51B6A2417328D005E7000 /* AudioKitUI.xcframework */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | C4067FE21F5D411900FA09A4 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = C4067FD81F5D411800FA09A4 /* DropDown.xcodeproj */; 28 | proxyType = 2; 29 | remoteGlobalIDString = 0AB5D8711D0EEECD002D3A17; 30 | remoteInfo = DropDown; 31 | }; 32 | C4067FE61F5D415C00FA09A4 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = C4067FD81F5D411800FA09A4 /* DropDown.xcodeproj */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 0AB5D8701D0EEECD002D3A17; 37 | remoteInfo = DropDown; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | B1756EC81F411E1400792670 /* Embed Frameworks */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = ""; 46 | dstSubfolderSpec = 10; 47 | files = ( 48 | C4067FE51F5D415C00FA09A4 /* DropDown.framework in Embed Frameworks */, 49 | ); 50 | name = "Embed Frameworks"; 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | B1756EA71F411D5A00792670 /* AudioUnitManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AudioUnitManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | B1756EAA1F411D5A00792670 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 58 | B1756EAC1F411D5A00792670 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 59 | B1756EAF1F411D5A00792670 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | B1756EB11F411D5A00792670 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | B1756EB41F411D5A00792670 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | B1756EB61F411D5A00792670 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | B1756EC91F41FD3A00792670 /* AudioUnitGenericView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioUnitGenericView.swift; sourceTree = ""; }; 64 | C4067FD81F5D411800FA09A4 /* DropDown.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = DropDown.xcodeproj; path = AudioUnitManager/DropDown/DropDown.xcodeproj; sourceTree = ""; }; 65 | C4704C2E1F5D2B3C004C087E /* Organ.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = Organ.wav; path = ../../../Common/Organ.wav; sourceTree = ""; }; 66 | C4704C391F5D2C15004C087E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 67 | EAF51AEA241723E7005E7000 /* AudioKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AudioKit.xcframework; path = ../../../Frameworks/AudioKit.xcframework; sourceTree = ""; }; 68 | EAF51B6A2417328D005E7000 /* AudioKitUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AudioKitUI.xcframework; path = ../../../Frameworks/AudioKitUI.xcframework; sourceTree = ""; }; 69 | /* End PBXFileReference section */ 70 | 71 | /* Begin PBXFrameworksBuildPhase section */ 72 | B1756EA41F411D5A00792670 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | C4067FE41F5D415C00FA09A4 /* DropDown.framework in Frameworks */, 77 | EAF51B6B2417328D005E7000 /* AudioKitUI.xcframework in Frameworks */, 78 | EAF51AEB241723E7005E7000 /* AudioKit.xcframework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXFrameworksBuildPhase section */ 83 | 84 | /* Begin PBXGroup section */ 85 | B1756E9E1F411D5A00792670 = { 86 | isa = PBXGroup; 87 | children = ( 88 | C4067FD81F5D411800FA09A4 /* DropDown.xcodeproj */, 89 | B1756EA91F411D5A00792670 /* AudioUnitManager */, 90 | B1756EA81F411D5A00792670 /* Products */, 91 | EAF51AE9241723E6005E7000 /* Frameworks */, 92 | ); 93 | sourceTree = ""; 94 | }; 95 | B1756EA81F411D5A00792670 /* Products */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | B1756EA71F411D5A00792670 /* AudioUnitManager.app */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | B1756EA91F411D5A00792670 /* AudioUnitManager */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | B1756EAA1F411D5A00792670 /* AppDelegate.swift */, 107 | B1756EAC1F411D5A00792670 /* ViewController.swift */, 108 | B1756EC91F41FD3A00792670 /* AudioUnitGenericView.swift */, 109 | C4704C391F5D2C15004C087E /* Default-568h@2x.png */, 110 | B1756EAE1F411D5A00792670 /* Main.storyboard */, 111 | B1756EB11F411D5A00792670 /* Assets.xcassets */, 112 | B1756EB31F411D5A00792670 /* LaunchScreen.storyboard */, 113 | B1756EB61F411D5A00792670 /* Info.plist */, 114 | C4704C2E1F5D2B3C004C087E /* Organ.wav */, 115 | ); 116 | path = AudioUnitManager; 117 | sourceTree = ""; 118 | }; 119 | C4067FD91F5D411800FA09A4 /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | C4067FE31F5D411900FA09A4 /* DropDown.framework */, 123 | ); 124 | name = Products; 125 | sourceTree = ""; 126 | }; 127 | EAF51AE9241723E6005E7000 /* Frameworks */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | EAF51B6A2417328D005E7000 /* AudioKitUI.xcframework */, 131 | EAF51AEA241723E7005E7000 /* AudioKit.xcframework */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | B1756EA61F411D5A00792670 /* AudioUnitManager */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = B1756EB91F411D5A00792670 /* Build configuration list for PBXNativeTarget "AudioUnitManager" */; 142 | buildPhases = ( 143 | B1756EA31F411D5A00792670 /* Sources */, 144 | B1756EA41F411D5A00792670 /* Frameworks */, 145 | B1756EA51F411D5A00792670 /* Resources */, 146 | B1756EC81F411E1400792670 /* Embed Frameworks */, 147 | ); 148 | buildRules = ( 149 | ); 150 | dependencies = ( 151 | C4067FE71F5D415C00FA09A4 /* PBXTargetDependency */, 152 | ); 153 | name = AudioUnitManager; 154 | productName = "AudioUnitManagerExample-iOS"; 155 | productReference = B1756EA71F411D5A00792670 /* AudioUnitManager.app */; 156 | productType = "com.apple.product-type.application"; 157 | }; 158 | /* End PBXNativeTarget section */ 159 | 160 | /* Begin PBXProject section */ 161 | B1756E9F1F411D5A00792670 /* Project object */ = { 162 | isa = PBXProject; 163 | attributes = { 164 | LastSwiftUpdateCheck = 0830; 165 | LastUpgradeCheck = 1020; 166 | ORGANIZATIONNAME = "Ryan Francesconi"; 167 | TargetAttributes = { 168 | B1756EA61F411D5A00792670 = { 169 | CreatedOnToolsVersion = 8.3.3; 170 | DevelopmentTeam = 9W69ZP8S5F; 171 | LastSwiftMigration = 1020; 172 | ProvisioningStyle = Automatic; 173 | SystemCapabilities = { 174 | com.apple.BackgroundModes = { 175 | enabled = 1; 176 | }; 177 | }; 178 | }; 179 | }; 180 | }; 181 | buildConfigurationList = B1756EA21F411D5A00792670 /* Build configuration list for PBXProject "AudioUnitManager" */; 182 | compatibilityVersion = "Xcode 3.2"; 183 | developmentRegion = en; 184 | hasScannedForEncodings = 0; 185 | knownRegions = ( 186 | en, 187 | Base, 188 | ); 189 | mainGroup = B1756E9E1F411D5A00792670; 190 | productRefGroup = B1756EA81F411D5A00792670 /* Products */; 191 | projectDirPath = ""; 192 | projectReferences = ( 193 | { 194 | ProductGroup = C4067FD91F5D411800FA09A4 /* Products */; 195 | ProjectRef = C4067FD81F5D411800FA09A4 /* DropDown.xcodeproj */; 196 | }, 197 | ); 198 | projectRoot = ""; 199 | targets = ( 200 | B1756EA61F411D5A00792670 /* AudioUnitManager */, 201 | ); 202 | }; 203 | /* End PBXProject section */ 204 | 205 | /* Begin PBXReferenceProxy section */ 206 | C4067FE31F5D411900FA09A4 /* DropDown.framework */ = { 207 | isa = PBXReferenceProxy; 208 | fileType = wrapper.framework; 209 | path = DropDown.framework; 210 | remoteRef = C4067FE21F5D411900FA09A4 /* PBXContainerItemProxy */; 211 | sourceTree = BUILT_PRODUCTS_DIR; 212 | }; 213 | /* End PBXReferenceProxy section */ 214 | 215 | /* Begin PBXResourcesBuildPhase section */ 216 | B1756EA51F411D5A00792670 /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | B1698AE51F684755008F397D /* Organ.wav in Resources */, 221 | B1756EB51F411D5A00792670 /* LaunchScreen.storyboard in Resources */, 222 | C4704C3A1F5D2C15004C087E /* Default-568h@2x.png in Resources */, 223 | B1756EB21F411D5A00792670 /* Assets.xcassets in Resources */, 224 | B1756EB01F411D5A00792670 /* Main.storyboard in Resources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXSourcesBuildPhase section */ 231 | B1756EA31F411D5A00792670 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | B1756EAD1F411D5A00792670 /* ViewController.swift in Sources */, 236 | B1756EAB1F411D5A00792670 /* AppDelegate.swift in Sources */, 237 | B1756ECA1F41FD3A00792670 /* AudioUnitGenericView.swift in Sources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXSourcesBuildPhase section */ 242 | 243 | /* Begin PBXTargetDependency section */ 244 | C4067FE71F5D415C00FA09A4 /* PBXTargetDependency */ = { 245 | isa = PBXTargetDependency; 246 | name = DropDown; 247 | targetProxy = C4067FE61F5D415C00FA09A4 /* PBXContainerItemProxy */; 248 | }; 249 | /* End PBXTargetDependency section */ 250 | 251 | /* Begin PBXVariantGroup section */ 252 | B1756EAE1F411D5A00792670 /* Main.storyboard */ = { 253 | isa = PBXVariantGroup; 254 | children = ( 255 | B1756EAF1F411D5A00792670 /* Base */, 256 | ); 257 | name = Main.storyboard; 258 | sourceTree = ""; 259 | }; 260 | B1756EB31F411D5A00792670 /* LaunchScreen.storyboard */ = { 261 | isa = PBXVariantGroup; 262 | children = ( 263 | B1756EB41F411D5A00792670 /* Base */, 264 | ); 265 | name = LaunchScreen.storyboard; 266 | sourceTree = ""; 267 | }; 268 | /* End PBXVariantGroup section */ 269 | 270 | /* Begin XCBuildConfiguration section */ 271 | B1756EB71F411D5A00792670 /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ALWAYS_SEARCH_USER_PATHS = NO; 275 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 276 | CLANG_ANALYZER_NONNULL = YES; 277 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_COMMA = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 287 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 288 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 289 | CLANG_WARN_EMPTY_BODY = YES; 290 | CLANG_WARN_ENUM_CONVERSION = YES; 291 | CLANG_WARN_INFINITE_RECURSION = YES; 292 | CLANG_WARN_INT_CONVERSION = YES; 293 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 294 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 295 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 297 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 298 | CLANG_WARN_STRICT_PROTOTYPES = YES; 299 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 300 | CLANG_WARN_UNREACHABLE_CODE = YES; 301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 302 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 303 | COPY_PHASE_STRIP = NO; 304 | DEBUG_ACTIVITY_MODE = ""; 305 | "DEBUG_ACTIVITY_MODE[sdk=iphonesimulator*]" = disable; 306 | DEBUG_INFORMATION_FORMAT = dwarf; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | ENABLE_TESTABILITY = YES; 309 | FRAMEWORK_SEARCH_PATHS = ""; 310 | GCC_C_LANGUAGE_STANDARD = gnu99; 311 | GCC_DYNAMIC_NO_PIC = NO; 312 | GCC_NO_COMMON_BLOCKS = YES; 313 | GCC_OPTIMIZATION_LEVEL = 0; 314 | GCC_PREPROCESSOR_DEFINITIONS = ( 315 | "DEBUG=1", 316 | "$(inherited)", 317 | ); 318 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 319 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 320 | GCC_WARN_UNDECLARED_SELECTOR = YES; 321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 322 | GCC_WARN_UNUSED_FUNCTION = YES; 323 | GCC_WARN_UNUSED_VARIABLE = YES; 324 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 325 | MTL_ENABLE_DEBUG_INFO = YES; 326 | ONLY_ACTIVE_ARCH = YES; 327 | SDKROOT = iphoneos; 328 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 329 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 330 | TARGETED_DEVICE_FAMILY = "1,2"; 331 | }; 332 | name = Debug; 333 | }; 334 | B1756EB81F411D5A00792670 /* Release */ = { 335 | isa = XCBuildConfiguration; 336 | buildSettings = { 337 | ALWAYS_SEARCH_USER_PATHS = NO; 338 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 339 | CLANG_ANALYZER_NONNULL = YES; 340 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 341 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 342 | CLANG_CXX_LIBRARY = "libc++"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 346 | CLANG_WARN_BOOL_CONVERSION = YES; 347 | CLANG_WARN_COMMA = YES; 348 | CLANG_WARN_CONSTANT_CONVERSION = YES; 349 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 351 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 352 | CLANG_WARN_EMPTY_BODY = YES; 353 | CLANG_WARN_ENUM_CONVERSION = YES; 354 | CLANG_WARN_INFINITE_RECURSION = YES; 355 | CLANG_WARN_INT_CONVERSION = YES; 356 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 357 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 358 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 359 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 360 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 361 | CLANG_WARN_STRICT_PROTOTYPES = YES; 362 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 363 | CLANG_WARN_UNREACHABLE_CODE = YES; 364 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 366 | COPY_PHASE_STRIP = NO; 367 | DEBUG_ACTIVITY_MODE = ""; 368 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 369 | ENABLE_NS_ASSERTIONS = NO; 370 | ENABLE_STRICT_OBJC_MSGSEND = YES; 371 | FRAMEWORK_SEARCH_PATHS = ""; 372 | GCC_C_LANGUAGE_STANDARD = gnu99; 373 | GCC_NO_COMMON_BLOCKS = YES; 374 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 375 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 376 | GCC_WARN_UNDECLARED_SELECTOR = YES; 377 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 378 | GCC_WARN_UNUSED_FUNCTION = YES; 379 | GCC_WARN_UNUSED_VARIABLE = YES; 380 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 381 | MTL_ENABLE_DEBUG_INFO = NO; 382 | SDKROOT = iphoneos; 383 | SWIFT_COMPILATION_MODE = wholemodule; 384 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 385 | TARGETED_DEVICE_FAMILY = "1,2"; 386 | VALIDATE_PRODUCT = YES; 387 | }; 388 | name = Release; 389 | }; 390 | B1756EBA1F411D5A00792670 /* Debug */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | CODE_SIGN_IDENTITY = "Apple Development"; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 397 | CODE_SIGN_STYLE = Automatic; 398 | DEVELOPMENT_TEAM = 9W69ZP8S5F; 399 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 400 | "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$(inherited)"; 401 | INFOPLIST_FILE = AudioUnitManager/Info.plist; 402 | LD_RUNPATH_SEARCH_PATHS = ( 403 | "$(inherited)", 404 | "@executable_path/Frameworks", 405 | ); 406 | OTHER_LDFLAGS = "-lc++"; 407 | PRODUCT_BUNDLE_IDENTIFIER = "io.AudioKit.AudioUnitManagerExample-iOS"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | PROVISIONING_PROFILE_SPECIFIER = ""; 410 | SWIFT_VERSION = 5.0; 411 | }; 412 | name = Debug; 413 | }; 414 | B1756EBB1F411D5A00792670 /* Release */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 419 | CODE_SIGN_IDENTITY = "Apple Development"; 420 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 421 | CODE_SIGN_STYLE = Automatic; 422 | DEVELOPMENT_TEAM = 9W69ZP8S5F; 423 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 424 | "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$(inherited)"; 425 | INFOPLIST_FILE = AudioUnitManager/Info.plist; 426 | LD_RUNPATH_SEARCH_PATHS = ( 427 | "$(inherited)", 428 | "@executable_path/Frameworks", 429 | ); 430 | OTHER_LDFLAGS = "-lc++"; 431 | PRODUCT_BUNDLE_IDENTIFIER = "io.AudioKit.AudioUnitManagerExample-iOS"; 432 | PRODUCT_NAME = "$(TARGET_NAME)"; 433 | PROVISIONING_PROFILE_SPECIFIER = ""; 434 | SWIFT_VERSION = 5.0; 435 | }; 436 | name = Release; 437 | }; 438 | /* End XCBuildConfiguration section */ 439 | 440 | /* Begin XCConfigurationList section */ 441 | B1756EA21F411D5A00792670 /* Build configuration list for PBXProject "AudioUnitManager" */ = { 442 | isa = XCConfigurationList; 443 | buildConfigurations = ( 444 | B1756EB71F411D5A00792670 /* Debug */, 445 | B1756EB81F411D5A00792670 /* Release */, 446 | ); 447 | defaultConfigurationIsVisible = 0; 448 | defaultConfigurationName = Release; 449 | }; 450 | B1756EB91F411D5A00792670 /* Build configuration list for PBXNativeTarget "AudioUnitManager" */ = { 451 | isa = XCConfigurationList; 452 | buildConfigurations = ( 453 | B1756EBA1F411D5A00792670 /* Debug */, 454 | B1756EBB1F411D5A00792670 /* Release */, 455 | ); 456 | defaultConfigurationIsVisible = 0; 457 | defaultConfigurationName = Release; 458 | }; 459 | /* End XCConfigurationList section */ 460 | }; 461 | rootObject = B1756E9F1F411D5A00792670 /* Project object */; 462 | } 463 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager.xcodeproj/xcshareddata/xcschemes/AudioUnitManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import UIKit 4 | 5 | @UIApplicationMain 6 | class AppDelegate: UIResponder, UIApplicationDelegate { 7 | 8 | var window: UIWindow? 9 | 10 | func application(_ application: UIApplication, 11 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 12 | // Override point for customization after application launch. 13 | return true 14 | } 15 | 16 | func applicationWillResignActive(_ application: UIApplication) { 17 | } 18 | 19 | func applicationDidEnterBackground(_ application: UIApplication) { 20 | } 21 | 22 | func applicationWillEnterForeground(_ application: UIApplication) { 23 | } 24 | 25 | func applicationDidBecomeActive(_ application: UIApplication) { 26 | } 27 | 28 | func applicationWillTerminate(_ application: UIApplication) { 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /iOS/AudioUnitManager/AudioUnitGenericView.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import UIKit 4 | import AVFoundation 5 | import AudioKit 6 | import AudioKitUI 7 | 8 | /// Creates a simple list of parameters linked to sliders 9 | class AudioUnitGenericView: UIView { 10 | 11 | convenience init(au: AVAudioUnit) { 12 | self.init() 13 | 14 | guard let tree = au.auAudioUnit.parameterTree else { return } 15 | 16 | var y = 5 17 | for param in tree.allParameters { 18 | let slider = AKSlider(property: param.displayName, 19 | value: param.value, 20 | range: param.minValue ... param.maxValue, 21 | format: "%0.1f", 22 | color: UIColor.darkGray, 23 | frame: CGRect(x: 20, y: y, width: 250, height: 50), 24 | callback: { (value) -> Void in 25 | 26 | // AUParameter references aren't persistent, so we need to refetch them 27 | // addresses aren't guarenteed either, but this is working right now 28 | if let p = au.auAudioUnit.parameterTree?.parameter(withAddress: param.address) { 29 | p.value = AUValue(value) 30 | } 31 | 32 | }) 33 | 34 | slider.textColor = UIColor.black 35 | slider.fontSize = 10 36 | slider.sliderBorderColor = UIColor.random() 37 | 38 | addSubview(slider) 39 | 40 | y += 50 41 | 42 | } 43 | 44 | self.frame = CGRect(x: 0, y: 0, width: 270, height: y) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 36 | 47 | 60 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 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 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/iOS/AudioUnitManager/Default-568h@2x.png -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/.github/contributing.md: -------------------------------------------------------------------------------- 1 | ### What where you trying to do 2 | 3 | A few lines to explain the goal. 4 | 5 | ### What actually happened 6 | 7 | A few lines to explain the bug. 8 | 9 | ### What you think went wrong (optional) 10 | 11 | If you have an idea, don't hesitate to comment it here! 12 | 13 | ### How to reproduce the issue 14 | 15 | Put some code here if necessary. 16 | 17 | ### Details 18 | 19 | OS version, logs or screenshots. 20 | 21 | Thank you for your contribution! 👍 22 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/.gitignore: -------------------------------------------------------------------------------- 1 | ### Swift ### 2 | # Xcode 3 | # 4 | build/ 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | *.xccheckout 15 | *.moved-aside 16 | DerivedData 17 | *.hmap 18 | *.ipa 19 | *.xcuserstate 20 | 21 | # CocoaPods 22 | # 23 | # We recommend against adding the Pods directory to your .gitignore. However 24 | # you should judge for yourself, the pros and cons are mentioned at: 25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 26 | # 27 | # Pods/ 28 | 29 | # Carthage 30 | # 31 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 32 | # Carthage/Checkouts 33 | 34 | Carthage/Build 35 | 36 | # Mac OS X 37 | .DS_Store 38 | 39 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0AB5D8881D0EEEFF002D3A17 /* DPDConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D87E1D0EEEFF002D3A17 /* DPDConstants.swift */; }; 11 | 0AB5D8891D0EEEFF002D3A17 /* DPDKeyboardListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D87F1D0EEEFF002D3A17 /* DPDKeyboardListener.swift */; }; 12 | 0AB5D88A1D0EEEFF002D3A17 /* DPDUIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D8801D0EEEFF002D3A17 /* DPDUIView+Extension.swift */; }; 13 | 0AB5D88B1D0EEEFF002D3A17 /* DropDownCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0AB5D8821D0EEEFF002D3A17 /* DropDownCell.xib */; }; 14 | 0AB5D88C1D0EEEFF002D3A17 /* DropDown+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D8841D0EEEFF002D3A17 /* DropDown+Appearance.swift */; }; 15 | 0AB5D88D1D0EEEFF002D3A17 /* DropDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D8851D0EEEFF002D3A17 /* DropDown.swift */; }; 16 | 0AB5D88E1D0EEEFF002D3A17 /* DropDownCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB5D8861D0EEEFF002D3A17 /* DropDownCell.swift */; }; 17 | 0AB5D88F1D0EEEFF002D3A17 /* DropDown.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AB5D8871D0EEEFF002D3A17 /* DropDown.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 0AB5D8711D0EEECD002D3A17 /* DropDown.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DropDown.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 0AB5D8751D0EEECD002D3A17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | 0AB5D87E1D0EEEFF002D3A17 /* DPDConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPDConstants.swift; sourceTree = ""; }; 24 | 0AB5D87F1D0EEEFF002D3A17 /* DPDKeyboardListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPDKeyboardListener.swift; sourceTree = ""; }; 25 | 0AB5D8801D0EEEFF002D3A17 /* DPDUIView+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DPDUIView+Extension.swift"; sourceTree = ""; }; 26 | 0AB5D8821D0EEEFF002D3A17 /* DropDownCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DropDownCell.xib; sourceTree = ""; }; 27 | 0AB5D8841D0EEEFF002D3A17 /* DropDown+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropDown+Appearance.swift"; sourceTree = ""; }; 28 | 0AB5D8851D0EEEFF002D3A17 /* DropDown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDown.swift; sourceTree = ""; }; 29 | 0AB5D8861D0EEEFF002D3A17 /* DropDownCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownCell.swift; sourceTree = ""; }; 30 | 0AB5D8871D0EEEFF002D3A17 /* DropDown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropDown.h; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 0AB5D86D1D0EEECD002D3A17 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 0A7644061B676C2300BF1A2D = { 45 | isa = PBXGroup; 46 | children = ( 47 | 0AB5D8721D0EEECD002D3A17 /* DropDown */, 48 | 0A7644101B676C2300BF1A2D /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | 0A7644101B676C2300BF1A2D /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 0AB5D8711D0EEECD002D3A17 /* DropDown.framework */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | 0AB5D8721D0EEECD002D3A17 /* DropDown */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 0AB5D8871D0EEEFF002D3A17 /* DropDown.h */, 64 | 0AB5D8751D0EEECD002D3A17 /* Info.plist */, 65 | 0AB5D87D1D0EEEFF002D3A17 /* helpers */, 66 | 0AB5D8811D0EEEFF002D3A17 /* resources */, 67 | 0AB5D8831D0EEEFF002D3A17 /* src */, 68 | ); 69 | path = DropDown; 70 | sourceTree = ""; 71 | }; 72 | 0AB5D87D1D0EEEFF002D3A17 /* helpers */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 0AB5D87E1D0EEEFF002D3A17 /* DPDConstants.swift */, 76 | 0AB5D87F1D0EEEFF002D3A17 /* DPDKeyboardListener.swift */, 77 | 0AB5D8801D0EEEFF002D3A17 /* DPDUIView+Extension.swift */, 78 | ); 79 | path = helpers; 80 | sourceTree = ""; 81 | }; 82 | 0AB5D8811D0EEEFF002D3A17 /* resources */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 0AB5D8821D0EEEFF002D3A17 /* DropDownCell.xib */, 86 | ); 87 | path = resources; 88 | sourceTree = ""; 89 | }; 90 | 0AB5D8831D0EEEFF002D3A17 /* src */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 0AB5D8841D0EEEFF002D3A17 /* DropDown+Appearance.swift */, 94 | 0AB5D8851D0EEEFF002D3A17 /* DropDown.swift */, 95 | 0AB5D8861D0EEEFF002D3A17 /* DropDownCell.swift */, 96 | ); 97 | path = src; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXHeadersBuildPhase section */ 103 | 0AB5D86E1D0EEECD002D3A17 /* Headers */ = { 104 | isa = PBXHeadersBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | 0AB5D88F1D0EEEFF002D3A17 /* DropDown.h in Headers */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXHeadersBuildPhase section */ 112 | 113 | /* Begin PBXNativeTarget section */ 114 | 0AB5D8701D0EEECD002D3A17 /* DropDown */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = 0AB5D87A1D0EEECD002D3A17 /* Build configuration list for PBXNativeTarget "DropDown" */; 117 | buildPhases = ( 118 | 0AB5D86C1D0EEECD002D3A17 /* Sources */, 119 | 0AB5D86D1D0EEECD002D3A17 /* Frameworks */, 120 | 0AB5D86E1D0EEECD002D3A17 /* Headers */, 121 | 0AB5D86F1D0EEECD002D3A17 /* Resources */, 122 | ); 123 | buildRules = ( 124 | ); 125 | dependencies = ( 126 | ); 127 | name = DropDown; 128 | productName = DropDown; 129 | productReference = 0AB5D8711D0EEECD002D3A17 /* DropDown.framework */; 130 | productType = "com.apple.product-type.framework"; 131 | }; 132 | /* End PBXNativeTarget section */ 133 | 134 | /* Begin PBXProject section */ 135 | 0A7644071B676C2300BF1A2D /* Project object */ = { 136 | isa = PBXProject; 137 | attributes = { 138 | LastSwiftUpdateCheck = 0730; 139 | LastUpgradeCheck = 1150; 140 | ORGANIZATIONNAME = "Kevin Hirsch"; 141 | TargetAttributes = { 142 | 0AB5D8701D0EEECD002D3A17 = { 143 | CreatedOnToolsVersion = 7.3.1; 144 | DevelopmentTeam = W22K9JG3J6; 145 | LastSwiftMigration = 1020; 146 | ProvisioningStyle = Automatic; 147 | }; 148 | }; 149 | }; 150 | buildConfigurationList = 0A76440A1B676C2300BF1A2D /* Build configuration list for PBXProject "DropDown" */; 151 | compatibilityVersion = "Xcode 3.2"; 152 | developmentRegion = en; 153 | hasScannedForEncodings = 0; 154 | knownRegions = ( 155 | en, 156 | Base, 157 | ); 158 | mainGroup = 0A7644061B676C2300BF1A2D; 159 | productRefGroup = 0A7644101B676C2300BF1A2D /* Products */; 160 | projectDirPath = ""; 161 | projectRoot = ""; 162 | targets = ( 163 | 0AB5D8701D0EEECD002D3A17 /* DropDown */, 164 | ); 165 | }; 166 | /* End PBXProject section */ 167 | 168 | /* Begin PBXResourcesBuildPhase section */ 169 | 0AB5D86F1D0EEECD002D3A17 /* Resources */ = { 170 | isa = PBXResourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | 0AB5D88B1D0EEEFF002D3A17 /* DropDownCell.xib in Resources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXResourcesBuildPhase section */ 178 | 179 | /* Begin PBXSourcesBuildPhase section */ 180 | 0AB5D86C1D0EEECD002D3A17 /* Sources */ = { 181 | isa = PBXSourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | 0AB5D88D1D0EEEFF002D3A17 /* DropDown.swift in Sources */, 185 | 0AB5D88C1D0EEEFF002D3A17 /* DropDown+Appearance.swift in Sources */, 186 | 0AB5D88A1D0EEEFF002D3A17 /* DPDUIView+Extension.swift in Sources */, 187 | 0AB5D8881D0EEEFF002D3A17 /* DPDConstants.swift in Sources */, 188 | 0AB5D88E1D0EEEFF002D3A17 /* DropDownCell.swift in Sources */, 189 | 0AB5D8891D0EEEFF002D3A17 /* DPDKeyboardListener.swift in Sources */, 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXSourcesBuildPhase section */ 194 | 195 | /* Begin XCBuildConfiguration section */ 196 | 0A76442C1B676C2300BF1A2D /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | ALWAYS_SEARCH_USER_PATHS = NO; 200 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 202 | CLANG_CXX_LIBRARY = "libc++"; 203 | CLANG_ENABLE_MODULES = YES; 204 | CLANG_ENABLE_OBJC_ARC = YES; 205 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 206 | CLANG_WARN_BOOL_CONVERSION = YES; 207 | CLANG_WARN_COMMA = YES; 208 | CLANG_WARN_CONSTANT_CONVERSION = YES; 209 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INFINITE_RECURSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 216 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 217 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNREACHABLE_CODE = YES; 223 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 224 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 225 | COPY_PHASE_STRIP = NO; 226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 227 | ENABLE_STRICT_OBJC_MSGSEND = YES; 228 | ENABLE_TESTABILITY = YES; 229 | GCC_C_LANGUAGE_STANDARD = gnu99; 230 | GCC_DYNAMIC_NO_PIC = NO; 231 | GCC_NO_COMMON_BLOCKS = YES; 232 | GCC_OPTIMIZATION_LEVEL = 0; 233 | GCC_PREPROCESSOR_DEFINITIONS = ( 234 | "DEBUG=1", 235 | "$(inherited)", 236 | ); 237 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 240 | GCC_WARN_UNDECLARED_SELECTOR = YES; 241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_VARIABLE = YES; 244 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 245 | MTL_ENABLE_DEBUG_INFO = YES; 246 | ONLY_ACTIVE_ARCH = YES; 247 | SDKROOT = iphoneos; 248 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 249 | SWIFT_VERSION = 3.0; 250 | }; 251 | name = Debug; 252 | }; 253 | 0A76442D1B676C2300BF1A2D /* Release */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 258 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 259 | CLANG_CXX_LIBRARY = "libc++"; 260 | CLANG_ENABLE_MODULES = YES; 261 | CLANG_ENABLE_OBJC_ARC = YES; 262 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_COMMA = YES; 265 | CLANG_WARN_CONSTANT_CONVERSION = YES; 266 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 273 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 284 | ENABLE_NS_ASSERTIONS = NO; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 295 | MTL_ENABLE_DEBUG_INFO = NO; 296 | SDKROOT = iphoneos; 297 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 298 | SWIFT_VERSION = 3.0; 299 | VALIDATE_PRODUCT = YES; 300 | }; 301 | name = Release; 302 | }; 303 | 0AB5D87B1D0EEECD002D3A17 /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CODE_SIGN_IDENTITY = ""; 308 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 309 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; 310 | CODE_SIGN_STYLE = Automatic; 311 | CURRENT_PROJECT_VERSION = 1; 312 | DEBUG_INFORMATION_FORMAT = dwarf; 313 | DEFINES_MODULE = YES; 314 | DEVELOPMENT_TEAM = W22K9JG3J6; 315 | DYLIB_COMPATIBILITY_VERSION = 1; 316 | DYLIB_CURRENT_VERSION = 1; 317 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 318 | ENABLE_TESTABILITY = YES; 319 | INFOPLIST_FILE = DropDown/Info.plist; 320 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 321 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 323 | PRODUCT_BUNDLE_IDENTIFIER = com.assistoLab.DropDown; 324 | PRODUCT_NAME = "$(TARGET_NAME)"; 325 | PROVISIONING_PROFILE_SPECIFIER = ""; 326 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; 327 | SKIP_INSTALL = YES; 328 | SWIFT_VERSION = 5.0; 329 | TARGETED_DEVICE_FAMILY = "1,2"; 330 | VERSIONING_SYSTEM = "apple-generic"; 331 | VERSION_INFO_PREFIX = ""; 332 | }; 333 | name = Debug; 334 | }; 335 | 0AB5D87C1D0EEECD002D3A17 /* Release */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | CLANG_ANALYZER_NONNULL = YES; 339 | CODE_SIGN_IDENTITY = ""; 340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 341 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; 342 | CODE_SIGN_STYLE = Automatic; 343 | CURRENT_PROJECT_VERSION = 1; 344 | DEFINES_MODULE = YES; 345 | DEVELOPMENT_TEAM = W22K9JG3J6; 346 | DYLIB_COMPATIBILITY_VERSION = 1; 347 | DYLIB_CURRENT_VERSION = 1; 348 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 349 | INFOPLIST_FILE = DropDown/Info.plist; 350 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 351 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = com.assistoLab.DropDown; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | PROVISIONING_PROFILE_SPECIFIER = ""; 356 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; 357 | SKIP_INSTALL = YES; 358 | SWIFT_VERSION = 5.0; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | VERSIONING_SYSTEM = "apple-generic"; 361 | VERSION_INFO_PREFIX = ""; 362 | }; 363 | name = Release; 364 | }; 365 | /* End XCBuildConfiguration section */ 366 | 367 | /* Begin XCConfigurationList section */ 368 | 0A76440A1B676C2300BF1A2D /* Build configuration list for PBXProject "DropDown" */ = { 369 | isa = XCConfigurationList; 370 | buildConfigurations = ( 371 | 0A76442C1B676C2300BF1A2D /* Debug */, 372 | 0A76442D1B676C2300BF1A2D /* Release */, 373 | ); 374 | defaultConfigurationIsVisible = 0; 375 | defaultConfigurationName = Release; 376 | }; 377 | 0AB5D87A1D0EEECD002D3A17 /* Build configuration list for PBXNativeTarget "DropDown" */ = { 378 | isa = XCConfigurationList; 379 | buildConfigurations = ( 380 | 0AB5D87B1D0EEECD002D3A17 /* Debug */, 381 | 0AB5D87C1D0EEECD002D3A17 /* Release */, 382 | ); 383 | defaultConfigurationIsVisible = 0; 384 | defaultConfigurationName = Release; 385 | }; 386 | /* End XCConfigurationList section */ 387 | }; 388 | rootObject = 0A7644071B676C2300BF1A2D /* Project object */; 389 | } 390 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown.xcodeproj/xcshareddata/xcschemes/DropDown.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/DropDown.h: -------------------------------------------------------------------------------- 1 | // 2 | // DropDown.h 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright © 2016 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for DropDown. 12 | FOUNDATION_EXPORT double DropDownVersionNumber; 13 | 14 | //! Project version string for DropDown. 15 | FOUNDATION_EXPORT const unsigned char DropDownVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/helpers/DPDConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright (c) 2015 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal struct DPDConstant { 12 | 13 | internal struct KeyPath { 14 | 15 | static let Frame = "frame" 16 | 17 | } 18 | 19 | internal struct ReusableIdentifier { 20 | 21 | static let DropDownCell = "DropDownCell" 22 | 23 | } 24 | 25 | internal struct UI { 26 | 27 | static let TextColor = UIColor.black 28 | static let TextFont = UIFont.systemFont(ofSize: 15) 29 | static let BackgroundColor = UIColor(white: 0.94, alpha: 1) 30 | static let SelectionBackgroundColor = UIColor(white: 0.89, alpha: 1) 31 | static let SeparatorColor = UIColor.clear 32 | static let CornerRadius: CGFloat = 2 33 | static let RowHeight: CGFloat = 44 34 | static let HeightPadding: CGFloat = 20 35 | 36 | struct Shadow { 37 | 38 | static let Color = UIColor.darkGray 39 | static let Offset = CGSize.zero 40 | static let Opacity: Float = 0.4 41 | static let Radius: CGFloat = 8 42 | 43 | } 44 | 45 | } 46 | 47 | internal struct Animation { 48 | 49 | static let Duration = 0.15 50 | static let EntranceOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseOut] 51 | static let ExitOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseIn] 52 | static let DownScaleTransform = CGAffineTransform(scaleX: 0.9, y: 0.9) 53 | 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/helpers/DPDKeyboardListener.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardListener.swift 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright (c) 2015 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal final class KeyboardListener { 12 | 13 | static let sharedInstance = KeyboardListener() 14 | 15 | fileprivate(set) var isVisible = false 16 | fileprivate(set) var keyboardFrame = CGRect.zero 17 | fileprivate var isListening = false 18 | 19 | deinit { 20 | stopListeningToKeyboard() 21 | } 22 | 23 | } 24 | 25 | // MARK: - Notifications 26 | 27 | extension KeyboardListener { 28 | 29 | func startListeningToKeyboard() { 30 | if isListening { 31 | return 32 | } 33 | 34 | isListening = true 35 | 36 | NotificationCenter.default.addObserver( 37 | self, 38 | selector: #selector(keyboardWillShow(_:)), 39 | name: UIResponder.keyboardWillShowNotification, 40 | object: nil) 41 | NotificationCenter.default.addObserver( 42 | self, 43 | selector: #selector(keyboardWillHide(_:)), 44 | name: UIResponder.keyboardWillHideNotification, 45 | object: nil) 46 | } 47 | 48 | func stopListeningToKeyboard() { 49 | NotificationCenter.default.removeObserver(self) 50 | } 51 | 52 | @objc 53 | fileprivate func keyboardWillShow(_ notification: Notification) { 54 | isVisible = true 55 | keyboardFrame = keyboardFrame(fromNotification: notification) 56 | } 57 | 58 | @objc 59 | fileprivate func keyboardWillHide(_ notification: Notification) { 60 | isVisible = false 61 | keyboardFrame = keyboardFrame(fromNotification: notification) 62 | } 63 | 64 | fileprivate func keyboardFrame(fromNotification notification: Notification) -> CGRect { 65 | return ((notification as NSNotification).userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/helpers/DPDUIView+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Constraints.swift 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright (c) 2015 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - Constraints 12 | 13 | internal extension UIView { 14 | 15 | func addConstraints(format: String, options: NSLayoutConstraint.FormatOptions = [], metrics: [String: AnyObject]? = nil, views: [String: UIView]) { 16 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: options, metrics: metrics, views: views)) 17 | } 18 | 19 | func addUniversalConstraints(format: String, options: NSLayoutConstraint.FormatOptions = [], metrics: [String: AnyObject]? = nil, views: [String: UIView]) { 20 | addConstraints(format: "H:\(format)", options: options, metrics: metrics, views: views) 21 | addConstraints(format: "V:\(format)", options: options, metrics: metrics, views: views) 22 | } 23 | 24 | } 25 | 26 | // MARK: - Bounds 27 | 28 | internal extension UIView { 29 | 30 | var windowFrame: CGRect? { 31 | return superview?.convert(frame, to: nil) 32 | } 33 | 34 | } 35 | 36 | internal extension UIWindow { 37 | 38 | static func visibleWindow() -> UIWindow? { 39 | var currentWindow = UIApplication.shared.keyWindow 40 | 41 | if currentWindow == nil { 42 | let frontToBackWindows = Array(UIApplication.shared.windows.reversed()) 43 | 44 | for window in frontToBackWindows { 45 | if window.windowLevel == UIWindow.Level.normal { 46 | currentWindow = window 47 | break 48 | } 49 | } 50 | } 51 | 52 | return currentWindow 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/resources/DropDownCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/src/DropDown+Appearance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DropDown+Appearance.swift 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright © 2016 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DropDown { 12 | 13 | public class func setupDefaultAppearance() { 14 | let appearance = DropDown.appearance() 15 | 16 | appearance.cellHeight = DPDConstant.UI.RowHeight 17 | appearance.backgroundColor = DPDConstant.UI.BackgroundColor 18 | appearance.selectionBackgroundColor = DPDConstant.UI.SelectionBackgroundColor 19 | appearance.separatorColor = DPDConstant.UI.SeparatorColor 20 | appearance.cornerRadius = DPDConstant.UI.CornerRadius 21 | appearance.shadowColor = DPDConstant.UI.Shadow.Color 22 | appearance.shadowOffset = DPDConstant.UI.Shadow.Offset 23 | appearance.shadowOpacity = DPDConstant.UI.Shadow.Opacity 24 | appearance.shadowRadius = DPDConstant.UI.Shadow.Radius 25 | appearance.animationduration = DPDConstant.Animation.Duration 26 | appearance.textColor = DPDConstant.UI.TextColor 27 | appearance.textFont = DPDConstant.UI.TextFont 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/DropDown/src/DropDownCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DropDownCellTableViewCell.swift 3 | // DropDown 4 | // 5 | // Created by Kevin Hirsch, revision history on Githbub. 6 | // Copyright (c) 2015 Kevin Hirsch. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class DropDownCell: UITableViewCell { 12 | 13 | //UI 14 | @IBOutlet open weak var optionLabel: UILabel! 15 | 16 | var selectedBackgroundColor: UIColor? 17 | 18 | } 19 | 20 | // MARK: - UI 21 | 22 | extension DropDownCell { 23 | 24 | override open func awakeFromNib() { 25 | super.awakeFromNib() 26 | 27 | backgroundColor = .clear 28 | } 29 | 30 | override open var isSelected: Bool { 31 | willSet { 32 | setSelected(newValue, animated: false) 33 | } 34 | } 35 | 36 | override open var isHighlighted: Bool { 37 | willSet { 38 | setSelected(newValue, animated: false) 39 | } 40 | } 41 | 42 | override open func setHighlighted(_ highlighted: Bool, animated: Bool) { 43 | setSelected(highlighted, animated: animated) 44 | } 45 | 46 | override open func setSelected(_ selected: Bool, animated: Bool) { 47 | let executeSelection: () -> Void = { [unowned self] in 48 | if let selectedBackgroundColor = self.selectedBackgroundColor { 49 | if selected { 50 | self.backgroundColor = selectedBackgroundColor 51 | } else { 52 | self.backgroundColor = .clear 53 | } 54 | } 55 | } 56 | 57 | if animated { 58 | UIView.animate(withDuration: 0.3, animations: { 59 | executeSelection() 60 | }) 61 | } else { 62 | executeSelection() 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/DropDown/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | DropDown 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIBackgroundModes 24 | 25 | audio 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /iOS/AudioUnitManager/ViewController.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AudioKit 4 | import AudioKitUI 5 | import DropDown 6 | import UIKit 7 | 8 | /// This example demonstrates how to use two different input sources 9 | /// (an AKAudioPlayer and an instrument Audio Unit) both sharing a 10 | /// single signal chain. 11 | class ViewController: UIViewController { 12 | @IBOutlet var playButton: UIButton! 13 | @IBOutlet var auContainer: UIScrollView! 14 | @IBOutlet var instrumentButton: UIButton! 15 | @IBOutlet var keyboardContainer: UIView! 16 | 17 | var currentAU: AudioUnitGenericView? 18 | 19 | var effectMenus = [DropDown?](repeating: nil, count: 3) 20 | var instrumentMenu = DropDown() 21 | var effectButtons = [UIButton?](repeating: nil, count: 3) 22 | 23 | var auManager: AKAudioUnitManager? 24 | var mixer = AKMixer() 25 | var player: AKPlayer? 26 | var auInstrument: AKAudioUnitInstrument? 27 | 28 | var keyboard: AKKeyboardView? 29 | 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | 33 | // create a manager instance 34 | auManager = AKAudioUnitManager() 35 | auManager?.delegate = self 36 | 37 | // async request a list of available effects units 38 | auManager?.requestEffects(completionHandler: { audioUnits in 39 | self.updateEffectsUI(audioUnits: audioUnits) 40 | }) 41 | 42 | // and then an instruments list 43 | auManager?.requestInstruments(completionHandler: { audioUnits in 44 | self.updateInstrumentsUI(audioUnits: audioUnits) 45 | }) 46 | 47 | // create some menus 48 | initDropDowns() 49 | 50 | guard let url = Bundle.main.resourceURL?.appendingPathComponent("Organ.wav"), 51 | FileManager.default.fileExists(atPath: url.path), 52 | let audioFile = try? AVAudioFile(forReading: url) else { 53 | AKLog("Didn't find source file") 54 | return 55 | } 56 | 57 | let player = AKPlayer(audioFile: audioFile) 58 | player.isLooping = true 59 | player.buffering = .always // clean loop 60 | mixer.addInput(player) 61 | 62 | // setup the initial input/output connections 63 | auManager?.input = player 64 | auManager?.output = mixer 65 | 66 | self.player = player 67 | 68 | // assign AudioKit's output to the mixer so it's easy to switch sources 69 | engine.output = mixer 70 | do { 71 | try engine.start() 72 | } catch { 73 | AKLog("AudioKit did not start!") 74 | } 75 | // bounds for the container aren't ready yet here, so async it to the next update 76 | // to pick up the correct size 77 | DispatchQueue.main.async { 78 | let kframe = CGRect(x: 0, 79 | y: 0, 80 | width: self.keyboardContainer.bounds.size.width, 81 | height: self.keyboardContainer.bounds.size.height) 82 | let keyboard = AKKeyboardView(frame: kframe) 83 | keyboard.delegate = self 84 | self.keyboardContainer.addSubview(keyboard) 85 | self.keyboard = keyboard 86 | } 87 | } 88 | 89 | // get a button by the tag set in the storyboard 90 | private func getEffectsButton(_ tag: Int) -> UIButton? { 91 | guard view != nil else { return nil } 92 | 93 | for sv in view.subviews { 94 | if let b = sv as? UIButton { 95 | if b.tag == tag { 96 | return b 97 | } 98 | } 99 | } 100 | return nil 101 | } 102 | 103 | private func initDropDowns() { 104 | for i in 0 ..< 3 { 105 | if let button = getEffectsButton(i) { 106 | effectButtons[i] = button 107 | } 108 | 109 | effectMenus[i] = DropDown() 110 | effectMenus[i]?.anchorView = view 111 | effectMenus[i]?.direction = .any 112 | effectMenus[i]?.textFont = UIFont.systemFont(ofSize: 10) 113 | 114 | effectMenus[i]?.selectionAction = { [weak self] (_: Int, name: String) in 115 | guard let strongSelf = self else { return } 116 | guard let auManager = strongSelf.auManager else { return } 117 | 118 | if name == "-" { 119 | auManager.removeEffect(at: i) 120 | strongSelf.currentAU?.removeFromSuperview() 121 | } else { 122 | auManager.insertAudioUnit(name: name, at: i) 123 | } 124 | 125 | strongSelf.effectButtons[i]?.setTitle(name, for: .normal) 126 | strongSelf.effectButtons[i]?.backgroundColor = UIColor.random() 127 | } 128 | } 129 | 130 | instrumentMenu.anchorView = view 131 | instrumentMenu.direction = .any 132 | instrumentMenu.textFont = UIFont.systemFont(ofSize: 10) 133 | instrumentMenu.selectionAction = { [weak self] (_: Int, name: String) in 134 | guard let strongSelf = self else { return } 135 | strongSelf.loadInstrument(name) 136 | } 137 | } 138 | 139 | /// tell the linked drop down to open 140 | @IBAction func handleChooseEffect(_ sender: UIButton) { 141 | guard sender.tag < 3 && sender.tag >= 0 else { return } 142 | effectMenus[sender.tag]?.show() 143 | } 144 | 145 | @IBAction func handleChooseInstrument(_ sender: UIButton) { 146 | instrumentMenu.show() 147 | } 148 | 149 | @IBAction func handlePlay(_ sender: UIButton) { 150 | guard let player = player else { return } 151 | 152 | // check to make sure the input is the player 153 | if auManager?.input !== player { 154 | auManager?.connectEffects(firstNode: player, lastNode: mixer) 155 | } 156 | 157 | if player.isPlaying { 158 | AKLog("Stop") 159 | player.stop() 160 | sender.setTitle("▶️", for: .normal) 161 | 162 | } else { 163 | AKLog("Play") 164 | player.play() 165 | sender.setTitle("⏹", for: .normal) 166 | } 167 | } 168 | 169 | /// this is called to fill the drop downs with a list of available audio units 170 | fileprivate func updateEffectsUI(audioUnits: [AVAudioUnitComponent]) { 171 | for i in 0 ..< 3 { 172 | var effectMenuData = ["-"] 173 | 174 | for component in audioUnits where component.name != "" { 175 | effectMenuData.append(component.name) 176 | } 177 | 178 | effectMenus[i]?.dataSource = effectMenuData 179 | } 180 | } 181 | 182 | fileprivate func updateInstrumentsUI(audioUnits: [AVAudioUnitComponent]) { 183 | guard auManager != nil else { return } 184 | 185 | var effectMenuData = ["-"] 186 | 187 | for component in audioUnits where component.name != "" { 188 | effectMenuData.append(component.name) 189 | } 190 | 191 | instrumentMenu.dataSource = effectMenuData 192 | } 193 | 194 | public func showAudioUnit(_ audioUnit: AVAudioUnit) { 195 | if currentAU != nil { 196 | currentAU?.removeFromSuperview() 197 | } 198 | 199 | let au = AudioUnitGenericView(au: audioUnit) 200 | auContainer.addSubview(au) 201 | auContainer.contentSize = au.frame.size 202 | currentAU = au 203 | } 204 | 205 | public func loadInstrument(_ name: String) { 206 | guard let auManager = auManager else { return } 207 | 208 | instrumentButton.setTitle("🎹: \(name)", for: .normal) 209 | 210 | if name == "-" { 211 | // reassign back to player 212 | auManager.input = player 213 | auManager.output = mixer 214 | 215 | } else { 216 | showInstrument(name) 217 | } 218 | } 219 | 220 | public func showInstrument(_ auname: String) { 221 | guard let auManager = auManager else { return } 222 | 223 | auManager.createInstrument(name: auname, completionHandler: { audioUnit in 224 | guard let audioUnit = audioUnit else { return } 225 | 226 | AKLog("* \(audioUnit.name) : Audio Unit created") 227 | 228 | if self.auInstrument != nil { 229 | // dispose 230 | } 231 | 232 | self.auInstrument = AKAudioUnitInstrument(audioUnit: audioUnit) 233 | 234 | if self.auInstrument == nil { 235 | return 236 | } 237 | self.auManager?.connectEffects(firstNode: self.auInstrument, lastNode: self.mixer) 238 | self.showAudioUnit(audioUnit) 239 | 240 | }) 241 | } 242 | } 243 | 244 | extension ViewController: AKAudioUnitManagerDelegate { 245 | func handleAudioUnitManagerNotification(_ notification: AKAudioUnitManager.Notification, 246 | audioUnitManager: AKAudioUnitManager) { 247 | guard let auManager = auManager, audioUnitManager == auManager else { return } 248 | 249 | switch notification { 250 | case .changed: 251 | updateEffectsUI(audioUnits: auManager.availableEffects) 252 | updateInstrumentsUI(audioUnits: auManager.availableInstruments) 253 | default: 254 | break 255 | } 256 | } 257 | 258 | func audioUnitManager(_ audioUnitManager: AKAudioUnitManager, didAddEffectAtIndex index: Int) { 259 | guard let player = player else { return } 260 | guard let auManager = auManager else { return } 261 | 262 | if player.isPlaying { 263 | player.stop() 264 | player.play() 265 | } 266 | 267 | if let audioUnit = auManager.effectsChain[index] { 268 | showAudioUnit(audioUnit) 269 | } 270 | } 271 | 272 | func audioUnitManager(_ audioUnitManager: AKAudioUnitManager, didRemoveEffectAtIndex index: Int) {} 273 | } 274 | 275 | extension ViewController: AKKeyboardDelegate { 276 | /// Note off events 277 | func noteOff(note: MIDINoteNumber) { 278 | guard let auInstrument = auInstrument else { return } 279 | auInstrument.stop(noteNumber: note, channel: 0) 280 | } 281 | 282 | /// Note on events 283 | func noteOn(note: MIDINoteNumber) { 284 | guard let auInstrument = auInstrument else { return } 285 | 286 | // check to make sure the input is the auInstrument 287 | if auManager?.input !== auInstrument { 288 | auManager?.connectEffects(firstNode: auInstrument, lastNode: mixer) 289 | } 290 | auInstrument.play(noteNumber: note, channel: 0) 291 | } 292 | } 293 | 294 | // Just some random nonsense 295 | 296 | extension CGFloat { 297 | static func random() -> CGFloat { 298 | return CGFloat(arc4random()) / CGFloat(UInt32.max) 299 | } 300 | } 301 | 302 | extension UIColor { 303 | static func random() -> UIColor { 304 | return UIColor(red: .random(), 305 | green: .random(), 306 | blue: .random(), 307 | alpha: 1.0) 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /macOS/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: # rule identifiers to exclude from running 2 | - file_header 3 | - attributes 4 | #- cyclomatic_complexity 5 | - type_name 6 | - todo 7 | 8 | 9 | type_body_length: 10 | - 800 # warning 11 | - 4000 # error 12 | 13 | function_body_length: 14 | - 400 # warning 15 | - 4000 # error 16 | 17 | line_length: 18 | - 120 # warning 19 | - 5000 # error 20 | 21 | file_length: 22 | - 1000 # warning 23 | - 10000 # error 24 | 25 | identifier_name: 26 | min_length: 27 | - 1 # warning 28 | 29 | force_cast: error 30 | force_unwrapping: error 31 | empty_count: error 32 | force_try: error 33 | for_where: error 34 | 35 | cyclomatic_complexity: 36 | - 10 # warning 37 | - 100 # error 38 | 39 | excluded: 40 | 41 | 42 | opt_in_rules: 43 | - legacy_constructor 44 | - closure_spacing 45 | - closure_end_indentation 46 | #- conditional_returns_on_newline 47 | - empty_count 48 | - explicit_init 49 | - first_where 50 | - nimble_operator 51 | #- number_separator 52 | - operator_usage_whitespace 53 | - overridden_super_call 54 | #- private_outlet 55 | - prohibited_super_call 56 | - redundant_nil_coalescing 57 | - switch_case_on_newline 58 | - file_length 59 | - weak_delegate 60 | - force_cast 61 | - object_literal 62 | - line_length 63 | - attributes 64 | - force_unwrapping 65 | - identifier_name 66 | - type_name 67 | - type_body_length 68 | - function_parameter_count 69 | - class_delegate_protocol 70 | - force_try -------------------------------------------------------------------------------- /macOS/AudioUnitManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B1119DDD1FDCE601003CB2BE /* AudioUnitManager+MIDI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1119DDC1FDCE601003CB2BE /* AudioUnitManager+MIDI.swift */; }; 11 | B118AB3A1F8A85B0000E9AB1 /* AudioUnitGenericWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B118AB381F8A85B0000E9AB1 /* AudioUnitGenericWindow.swift */; }; 12 | B118AB3B1F8A85B0000E9AB1 /* AudioUnitGenericWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = B118AB391F8A85B0000E9AB1 /* AudioUnitGenericWindow.xib */; }; 13 | B12311FF1F193EA200888115 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12311FE1F193EA200888115 /* AppDelegate.swift */; }; 14 | B12312011F193EA200888115 /* AudioUnitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12312001F193EA200888115 /* AudioUnitManager.swift */; }; 15 | B12312031F193EA200888115 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B12312021F193EA200888115 /* Assets.xcassets */; }; 16 | B12312061F193EA200888115 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B12312041F193EA200888115 /* Main.storyboard */; }; 17 | B12312131F193F6100888115 /* AudioUnitGenericView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12312101F193F6100888115 /* AudioUnitGenericView.swift */; }; 18 | B12312141F193F6100888115 /* AudioUnitParamSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12312111F193F6100888115 /* AudioUnitParamSlider.swift */; }; 19 | B123121D1F1944E200888115 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B123121C1F1944E200888115 /* Extensions.swift */; }; 20 | B1535FB81F87E8000028CC26 /* MenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1535FB71F87E7FF0028CC26 /* MenuButton.swift */; }; 21 | B1535FBA1F87E8090028CC26 /* ClosureMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1535FB91F87E8090028CC26 /* ClosureMenuItem.swift */; }; 22 | B18484741FD9A13400F65DA6 /* WaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18484731FD9A13400F65DA6 /* WaveformView.swift */; }; 23 | B186CF551F884FC40063CDB9 /* AudioUnitManager+Effects.swift in Sources */ = {isa = PBXBuildFile; fileRef = B186CF541F884FC40063CDB9 /* AudioUnitManager+Effects.swift */; }; 24 | B1B1B7EE2117F62700C5E395 /* AudioUnitToolbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B1B7EC2117F62700C5E395 /* AudioUnitToolbarController.swift */; }; 25 | B1B1B7EF2117F62700C5E395 /* AudioUnitToolbarController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1B1B7ED2117F62700C5E395 /* AudioUnitToolbarController.xib */; }; 26 | B1D2A7A61FDBB8400067DC39 /* AudioUnitManager+Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D2A7A51FDBB8400067DC39 /* AudioUnitManager+Player.swift */; }; 27 | B1FB61BF1F2E958400FF6DE7 /* InstrumentPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FB61BE1F2E958400FF6DE7 /* InstrumentPlayer.swift */; }; 28 | C4BEA50C2508839A007274A1 /* AudioKit in Frameworks */ = {isa = PBXBuildFile; productRef = C4BEA50B2508839A007274A1 /* AudioKit */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | B1119DDC1FDCE601003CB2BE /* AudioUnitManager+MIDI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioUnitManager+MIDI.swift"; sourceTree = ""; }; 33 | B118AB381F8A85B0000E9AB1 /* AudioUnitGenericWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitGenericWindow.swift; sourceTree = ""; }; 34 | B118AB391F8A85B0000E9AB1 /* AudioUnitGenericWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AudioUnitGenericWindow.xib; sourceTree = ""; }; 35 | B12311FB1F193EA100888115 /* AudioUnitManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AudioUnitManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | B12311FE1F193EA200888115 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | B12312001F193EA200888115 /* AudioUnitManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitManager.swift; sourceTree = ""; }; 38 | B12312021F193EA200888115 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 39 | B12312051F193EA200888115 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 40 | B12312071F193EA200888115 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | B12312101F193F6100888115 /* AudioUnitGenericView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioUnitGenericView.swift; sourceTree = ""; }; 42 | B12312111F193F6100888115 /* AudioUnitParamSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioUnitParamSlider.swift; sourceTree = ""; }; 43 | B123121C1F1944E200888115 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 44 | B1535FB71F87E7FF0028CC26 /* MenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuButton.swift; sourceTree = ""; }; 45 | B1535FB91F87E8090028CC26 /* ClosureMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosureMenuItem.swift; sourceTree = ""; }; 46 | B18484731FD9A13400F65DA6 /* WaveformView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaveformView.swift; sourceTree = ""; }; 47 | B186CF541F884FC40063CDB9 /* AudioUnitManager+Effects.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioUnitManager+Effects.swift"; sourceTree = ""; }; 48 | B1B1B7EC2117F62700C5E395 /* AudioUnitToolbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitToolbarController.swift; sourceTree = ""; }; 49 | B1B1B7ED2117F62700C5E395 /* AudioUnitToolbarController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AudioUnitToolbarController.xib; sourceTree = ""; }; 50 | B1D2A7A51FDBB8400067DC39 /* AudioUnitManager+Player.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioUnitManager+Player.swift"; sourceTree = ""; }; 51 | B1FB61BE1F2E958400FF6DE7 /* InstrumentPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstrumentPlayer.swift; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | B12311F81F193EA100888115 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | C4BEA50C2508839A007274A1 /* AudioKit in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | B118AB3C1F8A9A11000E9AB1 /* xib */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | B12312041F193EA200888115 /* Main.storyboard */, 70 | B118AB391F8A85B0000E9AB1 /* AudioUnitGenericWindow.xib */, 71 | B1B1B7ED2117F62700C5E395 /* AudioUnitToolbarController.xib */, 72 | ); 73 | name = xib; 74 | sourceTree = ""; 75 | }; 76 | B12311F21F193EA100888115 = { 77 | isa = PBXGroup; 78 | children = ( 79 | B12311FD1F193EA100888115 /* AudioUnitManager */, 80 | B12311FC1F193EA100888115 /* Products */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | B12311FC1F193EA100888115 /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | B12311FB1F193EA100888115 /* AudioUnitManager.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | B12311FD1F193EA100888115 /* AudioUnitManager */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | B12311FE1F193EA200888115 /* AppDelegate.swift */, 96 | B12312021F193EA200888115 /* Assets.xcassets */, 97 | B12312001F193EA200888115 /* AudioUnitManager.swift */, 98 | B186CF541F884FC40063CDB9 /* AudioUnitManager+Effects.swift */, 99 | B1119DDC1FDCE601003CB2BE /* AudioUnitManager+MIDI.swift */, 100 | B1D2A7A51FDBB8400067DC39 /* AudioUnitManager+Player.swift */, 101 | B1535FB61F87E7C70028CC26 /* Controls */, 102 | B123121C1F1944E200888115 /* Extensions.swift */, 103 | B12312071F193EA200888115 /* Info.plist */, 104 | B12312151F193F6900888115 /* MIDI */, 105 | B118AB3C1F8A9A11000E9AB1 /* xib */, 106 | ); 107 | path = AudioUnitManager; 108 | sourceTree = ""; 109 | }; 110 | B12312151F193F6900888115 /* MIDI */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | B1FB61BE1F2E958400FF6DE7 /* InstrumentPlayer.swift */, 114 | ); 115 | name = MIDI; 116 | sourceTree = ""; 117 | }; 118 | B1535FB61F87E7C70028CC26 /* Controls */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | B12312101F193F6100888115 /* AudioUnitGenericView.swift */, 122 | B118AB381F8A85B0000E9AB1 /* AudioUnitGenericWindow.swift */, 123 | B12312111F193F6100888115 /* AudioUnitParamSlider.swift */, 124 | B1B1B7EC2117F62700C5E395 /* AudioUnitToolbarController.swift */, 125 | B1535FB91F87E8090028CC26 /* ClosureMenuItem.swift */, 126 | B1535FB71F87E7FF0028CC26 /* MenuButton.swift */, 127 | B18484731FD9A13400F65DA6 /* WaveformView.swift */, 128 | ); 129 | name = Controls; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXNativeTarget section */ 135 | B12311FA1F193EA100888115 /* AudioUnitManager */ = { 136 | isa = PBXNativeTarget; 137 | buildConfigurationList = B123120A1F193EA200888115 /* Build configuration list for PBXNativeTarget "AudioUnitManager" */; 138 | buildPhases = ( 139 | B12311F71F193EA100888115 /* Sources */, 140 | B12311F81F193EA100888115 /* Frameworks */, 141 | B12311F91F193EA100888115 /* Resources */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = AudioUnitManager; 148 | packageProductDependencies = ( 149 | C4BEA50B2508839A007274A1 /* AudioKit */, 150 | ); 151 | productName = AudioUnitManagerExample; 152 | productReference = B12311FB1F193EA100888115 /* AudioUnitManager.app */; 153 | productType = "com.apple.product-type.application"; 154 | }; 155 | /* End PBXNativeTarget section */ 156 | 157 | /* Begin PBXProject section */ 158 | B12311F31F193EA100888115 /* Project object */ = { 159 | isa = PBXProject; 160 | attributes = { 161 | LastSwiftUpdateCheck = 0830; 162 | LastUpgradeCheck = 1130; 163 | ORGANIZATIONNAME = "Ryan Francesconi"; 164 | TargetAttributes = { 165 | B12311FA1F193EA100888115 = { 166 | CreatedOnToolsVersion = 8.3.3; 167 | LastSwiftMigration = 1020; 168 | ProvisioningStyle = Automatic; 169 | }; 170 | }; 171 | }; 172 | buildConfigurationList = B12311F61F193EA100888115 /* Build configuration list for PBXProject "AudioUnitManager" */; 173 | compatibilityVersion = "Xcode 9.3"; 174 | developmentRegion = en; 175 | hasScannedForEncodings = 0; 176 | knownRegions = ( 177 | en, 178 | Base, 179 | ); 180 | mainGroup = B12311F21F193EA100888115; 181 | packageReferences = ( 182 | C4BEA50A2508839A007274A1 /* XCRemoteSwiftPackageReference "AudioKit" */, 183 | ); 184 | productRefGroup = B12311FC1F193EA100888115 /* Products */; 185 | projectDirPath = ""; 186 | projectRoot = ""; 187 | targets = ( 188 | B12311FA1F193EA100888115 /* AudioUnitManager */, 189 | ); 190 | }; 191 | /* End PBXProject section */ 192 | 193 | /* Begin PBXResourcesBuildPhase section */ 194 | B12311F91F193EA100888115 /* Resources */ = { 195 | isa = PBXResourcesBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | B1B1B7EF2117F62700C5E395 /* AudioUnitToolbarController.xib in Resources */, 199 | B12312031F193EA200888115 /* Assets.xcassets in Resources */, 200 | B12312061F193EA200888115 /* Main.storyboard in Resources */, 201 | B118AB3B1F8A85B0000E9AB1 /* AudioUnitGenericWindow.xib in Resources */, 202 | ); 203 | runOnlyForDeploymentPostprocessing = 0; 204 | }; 205 | /* End PBXResourcesBuildPhase section */ 206 | 207 | /* Begin PBXSourcesBuildPhase section */ 208 | B12311F71F193EA100888115 /* Sources */ = { 209 | isa = PBXSourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | B1B1B7EE2117F62700C5E395 /* AudioUnitToolbarController.swift in Sources */, 213 | B118AB3A1F8A85B0000E9AB1 /* AudioUnitGenericWindow.swift in Sources */, 214 | B123121D1F1944E200888115 /* Extensions.swift in Sources */, 215 | B1535FBA1F87E8090028CC26 /* ClosureMenuItem.swift in Sources */, 216 | B12312011F193EA200888115 /* AudioUnitManager.swift in Sources */, 217 | B1535FB81F87E8000028CC26 /* MenuButton.swift in Sources */, 218 | B1119DDD1FDCE601003CB2BE /* AudioUnitManager+MIDI.swift in Sources */, 219 | B12312141F193F6100888115 /* AudioUnitParamSlider.swift in Sources */, 220 | B186CF551F884FC40063CDB9 /* AudioUnitManager+Effects.swift in Sources */, 221 | B1D2A7A61FDBB8400067DC39 /* AudioUnitManager+Player.swift in Sources */, 222 | B12311FF1F193EA200888115 /* AppDelegate.swift in Sources */, 223 | B12312131F193F6100888115 /* AudioUnitGenericView.swift in Sources */, 224 | B1FB61BF1F2E958400FF6DE7 /* InstrumentPlayer.swift in Sources */, 225 | B18484741FD9A13400F65DA6 /* WaveformView.swift in Sources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXSourcesBuildPhase section */ 230 | 231 | /* Begin PBXVariantGroup section */ 232 | B12312041F193EA200888115 /* Main.storyboard */ = { 233 | isa = PBXVariantGroup; 234 | children = ( 235 | B12312051F193EA200888115 /* Base */, 236 | ); 237 | name = Main.storyboard; 238 | sourceTree = ""; 239 | }; 240 | /* End PBXVariantGroup section */ 241 | 242 | /* Begin XCBuildConfiguration section */ 243 | B12312081F193EA200888115 /* Debug */ = { 244 | isa = XCBuildConfiguration; 245 | buildSettings = { 246 | ALWAYS_SEARCH_USER_PATHS = NO; 247 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 248 | CLANG_ANALYZER_NONNULL = YES; 249 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 251 | CLANG_CXX_LIBRARY = "libc++"; 252 | CLANG_ENABLE_MODULES = YES; 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_COMMA = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 261 | CLANG_WARN_EMPTY_BODY = YES; 262 | CLANG_WARN_ENUM_CONVERSION = YES; 263 | CLANG_WARN_INFINITE_RECURSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 266 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 270 | CLANG_WARN_STRICT_PROTOTYPES = YES; 271 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | CODE_SIGN_IDENTITY = "-"; 275 | COPY_PHASE_STRIP = NO; 276 | DEBUG_INFORMATION_FORMAT = dwarf; 277 | ENABLE_STRICT_OBJC_MSGSEND = YES; 278 | ENABLE_TESTABILITY = YES; 279 | FRAMEWORK_SEARCH_PATHS = ""; 280 | GCC_C_LANGUAGE_STANDARD = gnu99; 281 | GCC_DYNAMIC_NO_PIC = NO; 282 | GCC_NO_COMMON_BLOCKS = YES; 283 | GCC_OPTIMIZATION_LEVEL = 0; 284 | GCC_PREPROCESSOR_DEFINITIONS = ( 285 | "DEBUG=1", 286 | "$(inherited)", 287 | ); 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | MACOSX_DEPLOYMENT_TARGET = 10.11; 295 | MTL_ENABLE_DEBUG_INFO = YES; 296 | ONLY_ACTIVE_ARCH = YES; 297 | SDKROOT = macosx; 298 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 299 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 300 | }; 301 | name = Debug; 302 | }; 303 | B12312091F193EA200888115 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 308 | CLANG_ANALYZER_NONNULL = YES; 309 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 311 | CLANG_CXX_LIBRARY = "libc++"; 312 | CLANG_ENABLE_MODULES = YES; 313 | CLANG_ENABLE_OBJC_ARC = YES; 314 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 315 | CLANG_WARN_BOOL_CONVERSION = YES; 316 | CLANG_WARN_COMMA = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 320 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 321 | CLANG_WARN_EMPTY_BODY = YES; 322 | CLANG_WARN_ENUM_CONVERSION = YES; 323 | CLANG_WARN_INFINITE_RECURSION = YES; 324 | CLANG_WARN_INT_CONVERSION = YES; 325 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 326 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 327 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 328 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 329 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 330 | CLANG_WARN_STRICT_PROTOTYPES = YES; 331 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 332 | CLANG_WARN_UNREACHABLE_CODE = YES; 333 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 334 | CODE_SIGN_IDENTITY = "-"; 335 | COPY_PHASE_STRIP = NO; 336 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 337 | ENABLE_NS_ASSERTIONS = NO; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | FRAMEWORK_SEARCH_PATHS = ""; 340 | GCC_C_LANGUAGE_STANDARD = gnu99; 341 | GCC_NO_COMMON_BLOCKS = YES; 342 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 343 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 344 | GCC_WARN_UNDECLARED_SELECTOR = YES; 345 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 346 | GCC_WARN_UNUSED_FUNCTION = YES; 347 | GCC_WARN_UNUSED_VARIABLE = YES; 348 | MACOSX_DEPLOYMENT_TARGET = 10.11; 349 | MTL_ENABLE_DEBUG_INFO = NO; 350 | SDKROOT = macosx; 351 | SWIFT_COMPILATION_MODE = wholemodule; 352 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 353 | }; 354 | name = Release; 355 | }; 356 | B123120B1F193EA200888115 /* Debug */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 360 | CODE_SIGN_IDENTITY = "-"; 361 | CODE_SIGN_STYLE = Automatic; 362 | COMBINE_HIDPI_IMAGES = YES; 363 | DEVELOPMENT_TEAM = ""; 364 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 365 | INFOPLIST_FILE = AudioUnitManager/Info.plist; 366 | LD_RUNPATH_SEARCH_PATHS = ( 367 | "$(inherited)", 368 | "@executable_path/../Frameworks", 369 | ); 370 | MACOSX_DEPLOYMENT_TARGET = 10.15; 371 | OTHER_LDFLAGS = "-lc++"; 372 | PRODUCT_BUNDLE_IDENTIFIER = io.audiokit.AudioUnitManager; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | PROVISIONING_PROFILE_SPECIFIER = ""; 375 | SWIFT_VERSION = 5.0; 376 | }; 377 | name = Debug; 378 | }; 379 | B123120C1F193EA200888115 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 383 | CODE_SIGN_IDENTITY = "-"; 384 | CODE_SIGN_STYLE = Automatic; 385 | COMBINE_HIDPI_IMAGES = YES; 386 | DEVELOPMENT_TEAM = ""; 387 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 388 | INFOPLIST_FILE = AudioUnitManager/Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = ( 390 | "$(inherited)", 391 | "@executable_path/../Frameworks", 392 | ); 393 | MACOSX_DEPLOYMENT_TARGET = 10.15; 394 | OTHER_LDFLAGS = "-lc++"; 395 | PRODUCT_BUNDLE_IDENTIFIER = io.audiokit.AudioUnitManager; 396 | PRODUCT_NAME = "$(TARGET_NAME)"; 397 | PROVISIONING_PROFILE_SPECIFIER = ""; 398 | SWIFT_VERSION = 5.0; 399 | }; 400 | name = Release; 401 | }; 402 | /* End XCBuildConfiguration section */ 403 | 404 | /* Begin XCConfigurationList section */ 405 | B12311F61F193EA100888115 /* Build configuration list for PBXProject "AudioUnitManager" */ = { 406 | isa = XCConfigurationList; 407 | buildConfigurations = ( 408 | B12312081F193EA200888115 /* Debug */, 409 | B12312091F193EA200888115 /* Release */, 410 | ); 411 | defaultConfigurationIsVisible = 0; 412 | defaultConfigurationName = Release; 413 | }; 414 | B123120A1F193EA200888115 /* Build configuration list for PBXNativeTarget "AudioUnitManager" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | B123120B1F193EA200888115 /* Debug */, 418 | B123120C1F193EA200888115 /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | /* End XCConfigurationList section */ 424 | 425 | /* Begin XCRemoteSwiftPackageReference section */ 426 | C4BEA50A2508839A007274A1 /* XCRemoteSwiftPackageReference "AudioKit" */ = { 427 | isa = XCRemoteSwiftPackageReference; 428 | repositoryURL = "https://github.com/AudioKit/AudioKit/"; 429 | requirement = { 430 | branch = "v5-develop"; 431 | kind = branch; 432 | }; 433 | }; 434 | /* End XCRemoteSwiftPackageReference section */ 435 | 436 | /* Begin XCSwiftPackageProductDependency section */ 437 | C4BEA50B2508839A007274A1 /* AudioKit */ = { 438 | isa = XCSwiftPackageProductDependency; 439 | package = C4BEA50A2508839A007274A1 /* XCRemoteSwiftPackageReference "AudioKit" */; 440 | productName = AudioKit; 441 | }; 442 | /* End XCSwiftPackageProductDependency section */ 443 | }; 444 | rootObject = B12311F31F193EA100888115 /* Project object */; 445 | } 446 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "AudioKit", 6 | "repositoryURL": "https://github.com/AudioKit/AudioKit/", 7 | "state": { 8 | "branch": "v5-develop", 9 | "revision": "a7dc7f28b5f116ebb3b8a71e2d2425bbefca48e1", 10 | "version": null 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import Cocoa 4 | 5 | @NSApplicationMain 6 | class AppDelegate: NSObject, NSApplicationDelegate { 7 | func applicationDidFinishLaunching(_ aNotification: Notification) { 8 | // Insert code here to initialize your application 9 | 10 | NotificationCenter.default.post(name: Notification.Name("AudioUnitManager.handleApplicationInit"), object: nil) 11 | } 12 | 13 | func applicationWillTerminate(_ aNotification: Notification) { 14 | // Insert code here to tear down your application 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-1024.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-128.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-16.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-256.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-32.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-512.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AudioKit/AudioUnitManager/80eda0dba6fbf0578aebf7bd047e4f37abddb9f6/macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/AudioUnitIcon-64.png -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "AudioUnitIcon-16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "AudioUnitIcon-32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "AudioUnitIcon-32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "AudioUnitIcon-64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "AudioUnitIcon-128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "AudioUnitIcon-256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "AudioUnitIcon-256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "AudioUnitIcon-512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "AudioUnitIcon-512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "AudioUnitIcon-1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Assets.xcassets/Faded Red.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.600", 13 | "alpha" : "0.500", 14 | "blue" : "0.300", 15 | "green" : "0.300" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitGenericView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GenericAudioUnitView.swift 3 | // 4 | // Created by Ryan Francesconi, revision history on Githbub. 5 | // Copyright © 2018 AudioKit. All rights reserved. 6 | // 7 | 8 | import AVFoundation 9 | import Cocoa 10 | 11 | /// Creates a simple list of parameters linked to sliders 12 | class AudioUnitGenericView: NSView { 13 | open var name: String = "" 14 | open var preferredWidth: CGFloat = 360 15 | open var preferredHeight: CGFloat = 400 16 | 17 | override var isFlipped: Bool { 18 | return true 19 | } 20 | 21 | open var opaqueBackground: Bool = true 22 | 23 | open var backgroundColor: NSColor = NSColor.darkGray { 24 | didSet { 25 | needsDisplay = true 26 | } 27 | } 28 | 29 | override func draw(_ dirtyRect: NSRect) { 30 | super.draw(dirtyRect) 31 | 32 | if opaqueBackground { 33 | backgroundColor.setFill() 34 | let rect = NSRect(x: 0, y: 0, width: bounds.width, height: bounds.height) 35 | rect.fill() 36 | } 37 | } 38 | 39 | convenience init(audioUnit: AVAudioUnit) { 40 | self.init() 41 | wantsLayer = true 42 | 43 | if let cname = audioUnit.auAudioUnit.componentName { 44 | name = cname 45 | } 46 | 47 | let nameField = NSTextField() 48 | nameField.isSelectable = false 49 | nameField.isBordered = false 50 | nameField.isEditable = false 51 | nameField.alignment = .center 52 | nameField.font = NSFont.boldSystemFont(ofSize: 12) 53 | nameField.textColor = NSColor.white 54 | nameField.backgroundColor = NSColor.white.withAlphaComponent(0) 55 | nameField.stringValue = name 56 | nameField.frame = NSRect(x: 0, y: 4, width: preferredWidth, height: 20) 57 | addSubview(nameField) 58 | 59 | guard let tree = audioUnit.auAudioUnit.parameterTree else { return } 60 | 61 | var y = 5 62 | for param in tree.allParameters { 63 | y += 24 64 | 65 | let slider = AudioUnitParamSlider(audioUnit: audioUnit, param: param) 66 | slider.setFrameOrigin(NSPoint(x: 10, y: y)) 67 | 68 | addSubview(slider) 69 | DispatchQueue.main.async { 70 | slider.updateValue() 71 | } 72 | } 73 | preferredHeight = CGFloat(y + 50) 74 | frame.size = NSSize(width: preferredWidth, height: preferredHeight) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitGenericWindow.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AVFoundation 4 | import Cocoa 5 | 6 | class AudioUnitGenericWindow: NSWindowController { 7 | @IBOutlet var scrollView: NSScrollView! 8 | public let toolbar = AudioUnitToolbarController(nibName: "AudioUnitToolbarController", bundle: Bundle.main) 9 | 10 | internal var audioUnit: AVAudioUnit? 11 | 12 | convenience init(audioUnit: AVAudioUnit) { 13 | self.init(windowNibName: "AudioUnitGenericWindow") 14 | // contentViewController?.view.wantsLayer = true 15 | self.audioUnit = audioUnit 16 | toolbar.audioUnit = audioUnit 17 | } 18 | 19 | override func windowDidLoad() { 20 | super.windowDidLoad() 21 | window?.addTitlebarAccessoryViewController(toolbar) 22 | window?.appearance = AudioUnitManager.appearance 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitGenericWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitManager+Effects.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AudioKit 4 | import AVFoundation 5 | import Cocoa 6 | 7 | extension AudioUnitManager { 8 | internal func initManager() { 9 | internalManager.delegate = self 10 | 11 | internalManager.requestEffects(completionHandler: { audioUnits in 12 | // only allow stereo units right now... 13 | let audioUnits = audioUnits.filter { 14 | $0.supportsNumberInputChannels(2, outputChannels: 2) 15 | } 16 | self.updateEffectsUI(audioUnits: audioUnits) 17 | }) 18 | 19 | internalManager.requestInstruments(completionHandler: { audioUnits in 20 | self.updateInstrumentsUI(audioUnits: audioUnits) 21 | }) 22 | } 23 | 24 | //////////////////////////// 25 | 26 | func showEffect(at auIndex: Int, state: Bool) { 27 | if auIndex > internalManager.effectsChain.count - 1 { 28 | AKLog("index is out of range") 29 | return 30 | } 31 | 32 | if state { 33 | // get audio unit at the specified index 34 | if let au = internalManager.effectsChain[auIndex] { 35 | showAudioUnit(au, identifier: auIndex) 36 | 37 | } else { 38 | AKLog("Nothing at this index") 39 | } 40 | 41 | } else { 42 | if let w = getWindowFromIndentifier(auIndex) { 43 | w.close() 44 | } 45 | } 46 | } 47 | 48 | func handleEffectSelected(_ auname: String, identifier: Int) { 49 | AKLog("\(identifier) \(auname)") 50 | 51 | if auname == "-" { 52 | let blankName = "▼ Insert \(identifier + 1)" 53 | if let button = getEffectsButtonFromIdentifier(identifier) { 54 | button.state = .off 55 | } 56 | if let menu = getMenuFromIdentifier(identifier) { 57 | selectEffectInMenu(name: "-", identifier: identifier) 58 | menu.title = blankName 59 | } 60 | if let win = getWindowFromIndentifier(identifier) { 61 | win.close() 62 | } 63 | internalManager.removeEffect(at: identifier) 64 | return 65 | } 66 | 67 | internalManager.insertAudioUnit(name: auname, at: identifier) 68 | 69 | // select the item in the menu 70 | selectEffectInMenu(name: auname, identifier: identifier) 71 | } 72 | 73 | func selectEffectInMenu(name: String, identifier: Int) { 74 | guard let button = getMenuFromIdentifier(identifier) else { return } 75 | guard let menu = button.menu else { return } 76 | 77 | var parentMenu: NSMenuItem? 78 | 79 | for man in menu.items { 80 | guard let sub = man.submenu else { continue } 81 | 82 | man.state = .off 83 | for item in sub.items { 84 | item.state = (item.title == name) ? .on : .off 85 | 86 | if item.state == .on { 87 | parentMenu = man 88 | } 89 | } 90 | } 91 | 92 | if let pm = parentMenu { 93 | pm.state = .on 94 | button.title = "▶︎ \(name)" 95 | } 96 | } 97 | 98 | // MARK: - Build the effects menus 99 | 100 | fileprivate func updateEffectsUI(audioUnits: [AVAudioUnitComponent]) { 101 | var manufacturers = [String]() 102 | 103 | for component in audioUnits { 104 | let man = component.manufacturerName 105 | if !manufacturers.contains(man) { 106 | manufacturers.append(man) 107 | } 108 | } 109 | 110 | // going to put internal AUs in here 111 | manufacturers.append(akInternals) 112 | manufacturers.sort() 113 | 114 | // fill all the menus with the same list 115 | for sv in effectsContainer.subviews { 116 | guard let b = sv as? MenuButton else { continue } 117 | 118 | fillAUMenu(button: b, manufacturers: manufacturers, audioUnits: audioUnits) 119 | } 120 | } 121 | 122 | private func fillAUMenu(button: MenuButton, manufacturers: [String], audioUnits: [AVAudioUnitComponent]) { 123 | if button.menu == nil { 124 | let theMenu = NSMenu(title: "Effects") 125 | theMenu.font = NSFont.systemFont(ofSize: 10) 126 | button.menu = theMenu 127 | } 128 | 129 | button.menu?.removeAllItems() 130 | button.title = "▼ Insert \(button.tag + 1)" 131 | 132 | let blankItem = ClosureMenuItem(title: "-", closure: { [weak self] in 133 | guard let strongSelf = self else { return } 134 | strongSelf.handleEffectSelected("-", identifier: button.tag) 135 | }) 136 | 137 | button.menu?.addItem(blankItem) 138 | 139 | // first make a menu of manufacturers 140 | for man in manufacturers { 141 | let manItem = NSMenuItem() 142 | manItem.title = man 143 | manItem.submenu = NSMenu(title: man) 144 | button.menu?.addItem(manItem) 145 | } 146 | 147 | // then add each AU into it's parent folder 148 | for component in audioUnits { 149 | let item = ClosureMenuItem(title: component.name, closure: { [weak self] in 150 | guard let strongSelf = self else { return } 151 | strongSelf.handleEffectSelected(component.name, identifier: button.tag) 152 | }) 153 | 154 | guard let bmenu = button.menu else { continue } 155 | 156 | // manufacturer list 157 | for man in bmenu.items where man.title == component.manufacturerName { 158 | man.submenu?.addItem(item) 159 | } 160 | } 161 | 162 | let internalSubmenu = button.menu?.items.first(where: { $0.title == akInternals }) 163 | 164 | for name in AKAudioUnitManager.internalAudioUnits { 165 | let item = ClosureMenuItem(title: name, closure: { [weak self] in 166 | guard let strongSelf = self else { return } 167 | strongSelf.handleEffectSelected(name, identifier: button.tag) 168 | }) 169 | internalSubmenu?.submenu?.addItem(item) 170 | } 171 | } 172 | 173 | internal func getMenuFromIdentifier(_ tag: Int) -> MenuButton? { 174 | guard effectsContainer != nil else { return nil } 175 | 176 | for sv in effectsContainer.subviews { 177 | guard let b = sv as? MenuButton else { continue } 178 | if b.tag == tag { 179 | return b 180 | } 181 | } 182 | return nil 183 | } 184 | 185 | internal func getWindowFromIndentifier(_ tag: Int) -> NSWindow? { 186 | if let controller = getWindowController(at: tag) { 187 | return controller.window 188 | } 189 | return nil 190 | } 191 | 192 | private func getWindowController(at index: Int) -> AudioUnitGenericWindow? { 193 | if index < 0 || index > windowControllers.count - 1 { 194 | return nil 195 | } 196 | if let controller = windowControllers[index] { 197 | return controller 198 | } 199 | return nil 200 | } 201 | 202 | internal func getEffectsButtonFromIdentifier(_ buttonId: Int) -> NSButton? { 203 | guard effectsContainer != nil else { return nil } 204 | 205 | for sv in effectsContainer.subviews { 206 | if !sv.isKind(of: NSPopUpButton.self) { 207 | if let b = sv as? NSButton { 208 | if b.tag == buttonId { 209 | return b 210 | } 211 | } 212 | } 213 | } 214 | return nil 215 | } 216 | 217 | public func showAudioUnit(_ audioUnit: AVAudioUnit, identifier: Int) { 218 | if let previousController = getWindowController(at: identifier), 219 | previousController.audioUnit == audioUnit { 220 | // Log.debug("Same controller as before") 221 | 222 | if let unitWindow = previousController.window { 223 | // Log.debug("Showing window") 224 | unitWindow.orderFrontRegardless() 225 | previousController.showWindow(self) 226 | } 227 | return 228 | } 229 | 230 | var previousWindowOrigin: NSPoint? 231 | if let w = getWindowFromIndentifier(identifier) { 232 | previousWindowOrigin = w.frame.origin 233 | w.close() 234 | } 235 | 236 | var windowColor = NSColor.darkGray 237 | if let buttonColor = getMenuFromIdentifier(identifier)?.bgColor { 238 | windowColor = buttonColor 239 | } 240 | 241 | // first we ask the audio unit if it has a view controller inside it 242 | audioUnit.auAudioUnit.requestViewController { [weak self] viewController in 243 | guard let strongSelf = self else { return } 244 | 245 | var ui = viewController 246 | 247 | DispatchQueue.main.async { 248 | // if it doesn't - then an Audio Unit host's job is to create one for it 249 | if ui == nil { 250 | // AKLog("No ViewController for \(audioUnit.name )") 251 | ui = NSViewController() 252 | ui?.view = AudioUnitGenericView(audioUnit: audioUnit) 253 | } 254 | guard let theUI = ui else { return } 255 | 256 | strongSelf.createAUWindow(viewController: theUI, 257 | audioUnit: audioUnit, 258 | identifier: identifier, 259 | origin: previousWindowOrigin, 260 | color: windowColor) 261 | } 262 | } 263 | } 264 | 265 | private func createAUWindow(viewController: NSViewController, 266 | audioUnit: AVAudioUnit, 267 | identifier: Int, 268 | origin: NSPoint? = nil, 269 | color: NSColor? = nil) { 270 | let incomingFrame = viewController.view.frame 271 | 272 | AKLog("Audio Unit incoming frame: \(incomingFrame)") 273 | 274 | let windowController = AudioUnitGenericWindow(audioUnit: audioUnit) 275 | 276 | guard let unitWindow = windowController.window else { return } 277 | guard let auName = audioUnit.auAudioUnit.audioUnitName else { return } 278 | 279 | let winId = windowPrefix + String(identifier) 280 | 281 | let origin = origin ?? 282 | windowPositions[winId] ?? view.window?.frame.origin ?? NSPoint() 283 | 284 | let windowFrame = NSRect(origin: origin, 285 | size: NSSize(width: incomingFrame.width, height: incomingFrame.height + 30)) 286 | unitWindow.setFrame(windowFrame, display: false) 287 | 288 | unitWindow.title = "\(auName)" 289 | unitWindow.delegate = self 290 | unitWindow.identifier = NSUserInterfaceItemIdentifier(winId) 291 | 292 | if viewController.view.isKind(of: AudioUnitGenericView.self) { 293 | windowController.scrollView.documentView = viewController.view 294 | } else { 295 | windowController.scrollView?.removeFromSuperview() 296 | windowController.contentViewController = viewController 297 | } 298 | 299 | windowController.toolbar.audioUnit = audioUnit 300 | 301 | view.window?.addChildWindow(unitWindow, ordered: NSWindow.OrderingMode.above) 302 | 303 | if let button = getEffectsButtonFromIdentifier(identifier) { 304 | button.state = .on 305 | } 306 | 307 | if identifier < windowControllers.count { 308 | windowControllers[identifier] = windowController 309 | } 310 | } 311 | 312 | fileprivate func reconnect() { 313 | // is FM playing? 314 | if fmOscillator.isStarted { 315 | internalManager.connectEffects(firstNode: fmOscillator, lastNode: mixer) 316 | return 317 | } else if let auInstrument = auInstrument, !(player?.isPlaying ?? false) { 318 | internalManager.connectEffects(firstNode: auInstrument, lastNode: mixer) 319 | return 320 | } else if let player = player { 321 | let wasPlaying = player.isPlaying 322 | 323 | if wasPlaying { 324 | player.stop() 325 | } 326 | internalManager.connectEffects(firstNode: player, lastNode: mixer) 327 | 328 | if wasPlaying { 329 | player.play() 330 | } 331 | } 332 | } 333 | } 334 | 335 | extension AudioUnitManager: AKAudioUnitManagerDelegate { 336 | func handleAudioUnitManagerNotification(_ notification: AKAudioUnitManager.Notification, 337 | audioUnitManager: AKAudioUnitManager) { 338 | switch notification { 339 | case .changed: 340 | updateEffectsUI(audioUnits: internalManager.availableEffects) 341 | default: 342 | break 343 | } 344 | } 345 | 346 | func audioUnitManager(_ audioUnitManager: AKAudioUnitManager, didAddEffectAtIndex index: Int) { 347 | showEffect(at: index, state: true) 348 | reconnect() 349 | } 350 | 351 | func audioUnitManager(_ audioUnitManager: AKAudioUnitManager, didRemoveEffectAtIndex index: Int) { 352 | reconnect() 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitManager+MIDI.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AudioKit 4 | import Foundation 5 | 6 | extension AudioUnitManager: AKMIDIListener { 7 | internal func initMIDI() { 8 | midiManager = AKMIDI() 9 | midiManager?.addListener(self) 10 | initMIDIDevices() 11 | } 12 | 13 | internal func initMIDIDevices() { 14 | guard let devices = midiManager?.inputNames else { return } 15 | 16 | if !devices.isEmpty { 17 | midiDeviceSelector.removeAllItems() 18 | midiManager?.openInput(index: 0) 19 | 20 | for device in devices { 21 | AKLog("MIDI Device: \(device)") 22 | midiDeviceSelector.addItem(withTitle: device) 23 | } 24 | } 25 | } 26 | 27 | /// MIDI Setup has changed 28 | public func receivedMIDISetupChange() { 29 | initMIDIDevices() 30 | } 31 | 32 | func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) { 33 | let currentTime: Int = Int(mach_absolute_time()) 34 | 35 | // AKMIDI is sending duplicate noteOn messages??, don't let them be sent too quickly 36 | let sinceLastEvent = currentTime - lastMIDIEvent 37 | let isDupe = sinceLastEvent < 300_000 38 | 39 | if let auInstrument = auInstrument { 40 | if !isDupe { 41 | auInstrument.play(noteNumber: noteNumber, velocity: velocity, channel: channel) 42 | } else { 43 | // AKLog("Duplicate noteOn message sent") 44 | } 45 | } else { 46 | if !fmOscillator.isStarted { 47 | fmOscillator.start() 48 | } 49 | 50 | if fmTimer?.isValid ?? false { 51 | fmTimer?.invalidate() 52 | } 53 | let frequency = AKPolyphonicNode.tuningTable.frequency(forNoteNumber: noteNumber) 54 | fmOscillator.baseFrequency = AUValue(frequency) 55 | } 56 | lastMIDIEvent = currentTime 57 | } 58 | 59 | func receivedMIDINoteOff(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) { 60 | if let auInstrument = auInstrument { 61 | auInstrument.stop(noteNumber: noteNumber, channel: channel) 62 | 63 | } else if fmOscillator.isStarted { 64 | fmOscillator.stop() 65 | } 66 | } 67 | 68 | internal func playFM(state: Bool) { 69 | AKLog("playFM() \(state)") 70 | 71 | fmButton.state = state ? .on : .off 72 | 73 | if fmTimer?.isValid ?? false { 74 | fmTimer?.invalidate() 75 | } 76 | 77 | if state { 78 | if player?.isPlaying ?? false { 79 | handlePlay(state: false) 80 | } 81 | internalManager.connectEffects(firstNode: fmOscillator, lastNode: mixer) 82 | 83 | startEngine { 84 | self.fmOscillator.start() 85 | self.fmTimer = Timer.scheduledTimer(timeInterval: 0.2, 86 | target: self, 87 | selector: #selector(self.randomFM), 88 | userInfo: nil, 89 | repeats: true) 90 | } 91 | } else { 92 | fmOscillator.stop() 93 | } 94 | } 95 | 96 | @objc func randomFM() { 97 | let noteNumber = randomNumber(range: 0...127) 98 | let frequency = AKPolyphonicNode.tuningTable.frequency(forNoteNumber: MIDINoteNumber(noteNumber)) 99 | fmOscillator.baseFrequency = AUValue(frequency) 100 | fmOscillator.carrierMultiplier = AUValue(randomNumber(range: 10...100) / 100) 101 | fmOscillator.amplitude = AUValue(randomNumber(range: 10...100)) / 100 102 | } 103 | 104 | func randomNumber(range: ClosedRange = 100...500) -> Int { 105 | let min = range.lowerBound 106 | let max = range.upperBound 107 | return Int(arc4random_uniform(UInt32(1 + max - min))) + min 108 | } 109 | 110 | open func testAUInstrument(state: Bool) { 111 | AKLog("\(state)") 112 | guard let auInstrument = auInstrument else { return } 113 | 114 | instrumentPlayButton.state = state ? .on : .off 115 | 116 | if state { 117 | if player?.isPlaying ?? false { 118 | handlePlay(state: false) 119 | } 120 | internalManager.connectEffects(firstNode: auInstrument, lastNode: mixer) 121 | testPlayer = InstrumentPlayer(audioUnit: auInstrument.midiInstrument?.auAudioUnit) 122 | testPlayer?.play() 123 | } else { 124 | testPlayer?.stop() 125 | } 126 | } 127 | 128 | internal func updateInstrumentsUI(audioUnits: [AVAudioUnitComponent]) { 129 | auInstrumentSelector.removeAllItems() 130 | auInstrumentSelector.addItem(withTitle: "-") 131 | 132 | for component in audioUnits where component.name != "" { 133 | auInstrumentSelector.addItem(withTitle: component.name) 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitManager+Player.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AudioKit 4 | import Cocoa 5 | 6 | extension AudioUnitManager { 7 | internal func handlePlay(state: Bool) { 8 | guard let player = player else { return } 9 | // stop 10 | if player.isPlaying { 11 | player.pause() 12 | } 13 | 14 | playButton.state = state ? .on : .off 15 | 16 | if state { 17 | // play 18 | 19 | // just turning off the synths if they are playing 20 | if fmOscillator.isStarted { 21 | fmButton?.state = .off 22 | fmOscillator.stop() 23 | } 24 | 25 | if auInstrument != nil { 26 | instrumentPlayButton.state = .off 27 | } 28 | 29 | // then attach the effects chain if needed 30 | if internalManager.input !== player { 31 | internalManager.connectEffects(firstNode: player, lastNode: mixer) 32 | } 33 | startEngine { 34 | // player.volume = 1 // AOP no volume on player yet 35 | player.play(from: self.waveform?.position ?? 0) 36 | self.startAudioTimer() 37 | } 38 | } else { 39 | if engine.avEngine.isRunning { 40 | // just turns off reverb tails or delay lines etc 41 | internalManager.reset() 42 | } 43 | stopAudioTimer() 44 | } 45 | } 46 | 47 | func handleRewind() { 48 | guard let player = player else { return } 49 | let wasPlaying = player.isPlaying 50 | if wasPlaying { 51 | handlePlay(state: false) 52 | } 53 | 54 | player.startTime = 0 55 | waveform?.position = 0 56 | updateTimeDisplay(0) 57 | 58 | if wasPlaying { 59 | DispatchQueue.main.async { 60 | self.handlePlay(state: true) 61 | } 62 | } 63 | } 64 | 65 | func handleAudioComplete() { 66 | guard let player = player else { return } 67 | // AKLog("handleAudioComplete()") 68 | 69 | handlePlay(state: false) 70 | player.startTime = 0 71 | handleRewindButton(rewindButton) 72 | } 73 | 74 | /// open an audio URL for playing 75 | func open(url: URL) { 76 | engine.stop() 77 | handlePlay(state: false) 78 | 79 | if player == nil { 80 | createPlayer(url: url) 81 | 82 | } else { 83 | do { 84 | try player?.load(url: url) 85 | } catch let err as NSError { 86 | AKLog(err) 87 | createPlayer(url: url) 88 | } 89 | } 90 | 91 | playButton.isEnabled = true 92 | fileField.stringValue = "🔈 \(url.lastPathComponent)" 93 | 94 | if waveform != nil { 95 | waveform?.dispose() 96 | } 97 | 98 | // create the waveform 99 | waveform = WaveformView(url: url, 100 | color: NSColor(calibratedRed: 0.79, green: 0.372, blue: 0.191, alpha: 1)) 101 | 102 | guard let waveform = waveform else { return } 103 | 104 | waveformContainer.addSubview(waveform) 105 | waveform.frame = waveformContainer.frame 106 | waveform.fitToFrame() 107 | waveform.delegate = self 108 | audioEnabled = true 109 | audioNormalizedButton.state = .off 110 | } 111 | 112 | private func createPlayer(url: URL) { 113 | if player != nil { 114 | player?.detach() 115 | player = nil 116 | } 117 | 118 | player = AKPlayer(url: url) 119 | player?.completionHandler = handleAudioComplete 120 | player?.isLooping = isLooping 121 | player?.isNormalized = isNormalized 122 | player?.buffering = isBuffered ? .always : .dynamic 123 | 124 | internalManager.connectEffects(firstNode: player, lastNode: mixer) 125 | } 126 | 127 | func close() { 128 | fileField.stringValue = "" 129 | waveform?.dispose() 130 | player?.detach() 131 | player = nil 132 | audioEnabled = false 133 | } 134 | 135 | // this just moves the Timeline bar in the waveform 136 | internal func startAudioTimer() { 137 | stopAudioTimer() 138 | audioTimer = Timer.scheduledTimer(timeInterval: 0.02, 139 | target: self, 140 | selector: #selector(AudioUnitManager.updateWaveformDisplay), 141 | userInfo: nil, 142 | repeats: true) 143 | } 144 | 145 | internal func stopAudioTimer() { 146 | if audioTimer?.isValid ?? false { 147 | audioTimer?.invalidate() 148 | } 149 | } 150 | 151 | @objc private func updateWaveformDisplay() { 152 | guard let player = player else { return } 153 | // AKLog("\(player.currentTime)") 154 | waveform?.position = player.currentTime 155 | updateTimeDisplay(player.currentTime) 156 | } 157 | 158 | internal func updateTimeDisplay(_ time: Double) { 159 | timeField.stringValue = String.toClock(time) 160 | } 161 | } 162 | 163 | extension AudioUnitManager: WaveformViewDelegate { 164 | func loopChanged(source: WaveformView) { 165 | guard let player = player else { return } 166 | let wasPlaying = player.isPlaying 167 | if wasPlaying { 168 | handlePlay(state: false) 169 | } 170 | 171 | player.loop.start = source.loopStart 172 | player.loop.end = source.loopEnd 173 | player.endTime = source.loopEnd 174 | player.startTime = source.loopStart 175 | 176 | if wasPlaying { 177 | handlePlay(state: true) 178 | } 179 | } 180 | 181 | func waveformScrubbed(source: WaveformView, at time: Double) { 182 | updateTimeDisplay(time) 183 | } 184 | 185 | func waveformScrubComplete(source: WaveformView, at time: Double) { 186 | if audioPlaying { 187 | handlePlay(state: true) 188 | } else { 189 | player?.startTime = time 190 | } 191 | updateTimeDisplay(time) 192 | } 193 | 194 | func waveformSelected(source: WaveformView, at time: Double) { 195 | guard let player = player else { return } 196 | 197 | audioPlaying = player.isPlaying 198 | handlePlay(state: false) 199 | updateTimeDisplay(time) 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AudioUnitManager 3 | // 4 | // Created by Ryan Francesconi, revision history on Githbub. 5 | // Copyright © 2018 AudioKit. All rights reserved. 6 | // 7 | 8 | import AudioKit 9 | import AVFoundation 10 | import Cocoa 11 | 12 | /// An Example of how to create an AudioUnit Host application. 13 | /// This is also a demo for how to use AKPlayer. 14 | class AudioUnitManager: NSViewController { 15 | public static var appearance: NSAppearance? { 16 | if #available(macOS 10.14, *) { 17 | return NSAppearance(named: .darkAqua) 18 | } else { 19 | return NSAppearance(named: .vibrantDark) 20 | } 21 | } 22 | 23 | let akInternals = "AudioKit ★" 24 | let windowPrefix = "FX" 25 | 26 | @IBOutlet var effectsContainer: NSView! 27 | @IBOutlet var waveformContainer: NSView! 28 | @IBOutlet var timeField: NSTextField! 29 | @IBOutlet var playButton: NSButton! 30 | @IBOutlet var rewindButton: NSButton! 31 | @IBOutlet var loopButton: NSButton! 32 | @IBOutlet var audioBufferedButton: NSButton! 33 | @IBOutlet var audioReversedButton: NSButton! 34 | @IBOutlet var audioNormalizedButton: NSButton! 35 | @IBOutlet var instrumentPlayButton: NSButton! 36 | @IBOutlet var fileField: NSTextField! 37 | @IBOutlet var fmButton: NSButton! 38 | @IBOutlet var auInstrumentSelector: NSPopUpButton! 39 | @IBOutlet var midiDeviceSelector: NSPopUpButton! 40 | 41 | let engine = AKEngine() 42 | 43 | internal var lastMIDIEvent: Int = 0 44 | internal var audioTimer: Timer? 45 | internal var audioPlaying: Bool = false 46 | internal var openPanel: NSOpenPanel? 47 | internal var internalManager = AKAudioUnitManager(inserts: 6) 48 | internal var windowControllers = [AudioUnitGenericWindow?](repeating: nil, count: 6) 49 | internal var midiManager: AKMIDI? 50 | internal var player: AKPlayer? 51 | internal var waveform: WaveformView? 52 | internal var fmOscillator = AKFMOscillator() 53 | internal var mixer = AKMixer() 54 | internal var testPlayer: InstrumentPlayer? 55 | internal var fmTimer: Timer? 56 | internal var auInstrument: AKAudioUnitInstrument? 57 | internal var windowPositions = [String: NSPoint]() 58 | 59 | internal var peak: AVAudioPCMBuffer.Peak? 60 | 61 | public var isLooping: Bool { 62 | return loopButton.state == .on 63 | } 64 | 65 | public var isBuffered: Bool { 66 | return audioBufferedButton.state == .on 67 | } 68 | 69 | public var isNormalized: Bool { 70 | return audioNormalizedButton.state == .on 71 | } 72 | 73 | public var audioEnabled: Bool = false { 74 | didSet { 75 | audioReversedButton.isEnabled = audioEnabled 76 | playButton.isEnabled = audioEnabled 77 | rewindButton.isEnabled = audioEnabled 78 | loopButton.isEnabled = audioEnabled 79 | audioBufferedButton.isEnabled = audioEnabled 80 | audioNormalizedButton.isEnabled = audioEnabled 81 | } 82 | } 83 | 84 | // MARK: - init 85 | 86 | override func viewDidLoad() { 87 | super.viewDidLoad() 88 | initialize() 89 | } 90 | 91 | @objc func handleApplicationInit() { 92 | view.window?.delegate = self 93 | view.window?.appearance = AudioUnitManager.appearance 94 | view.appearance = AudioUnitManager.appearance 95 | } 96 | 97 | func initialize() { 98 | NotificationCenter.default.addObserver(self, 99 | selector: #selector(AudioUnitManager.handleApplicationInit), 100 | name: Notification.Name("AudioUnitManager.handleApplicationInit"), 101 | object: nil) 102 | let mainOutput = AKMixer() 103 | mainOutput.addInput(mixer) 104 | engine.output = mainOutput 105 | 106 | initManager() 107 | initMIDI() 108 | audioEnabled = false 109 | } 110 | 111 | internal func startEngine(completionHandler: AKCallback? = nil) { 112 | AKLog("* engine.isRunning: \(engine.avEngine.isRunning)") 113 | 114 | if !engine.avEngine.isRunning { 115 | do { 116 | try engine.start() 117 | } catch { 118 | AKLog("AudioKit did not start!") 119 | } 120 | 121 | DispatchQueue.main.asyncAfter(deadline: .now() + 1) { 122 | AKLog("Firing completionHandler...") 123 | completionHandler?() 124 | } 125 | return 126 | } 127 | completionHandler?() 128 | } 129 | 130 | // MARK: - Event Handlers 131 | 132 | @IBAction func openDocument(_ sender: AnyObject) { 133 | chooseAudio(sender) 134 | } 135 | 136 | @IBAction func closeDocument(_ sender: AnyObject) { 137 | close() 138 | } 139 | 140 | @IBAction func handleLoopButton(_ sender: NSButton) { 141 | let state = sender.state == .on 142 | guard let player = player else { return } 143 | guard let waveform = waveform else { return } 144 | 145 | let wasPlaying = player.isPlaying 146 | 147 | if wasPlaying { 148 | handlePlay(state: false) 149 | } 150 | 151 | player.isLooping = state 152 | waveform.isLooping = state 153 | audioBufferedButton.state = player.isBuffered ? .on : .off 154 | 155 | if !state { 156 | player.startTime = 0 157 | player.endTime = player.duration 158 | } 159 | 160 | if wasPlaying { 161 | DispatchQueue.main.async { 162 | self.handlePlay(state: true) 163 | } 164 | } 165 | } 166 | 167 | @IBAction func handleNormalizedButton(_ sender: NSButton) { 168 | guard let player = player else { return } 169 | 170 | player.buffering = sender.state == .on ? .always : .dynamic 171 | audioBufferedButton.state = sender.state 172 | player.isNormalized = sender.state == .on 173 | } 174 | 175 | @IBAction func handleBufferedButton(_ sender: NSButton) { 176 | player?.buffering = sender.state == .on ? .always : .dynamic 177 | } 178 | 179 | @IBAction func handleReversedButton(_ sender: NSButton) { 180 | guard let player = player else { return } 181 | guard let waveform = waveform else { return } 182 | 183 | AKLog("handleReversedButton() \(sender.state == .on)") 184 | let wasPlaying = player.isPlaying 185 | if wasPlaying { 186 | handlePlay(state: false) 187 | } 188 | player.isReversed = sender.state == .on 189 | waveform.isReversed = sender.state == .on 190 | audioBufferedButton.state = player.isBuffered ? .on : .off 191 | 192 | if wasPlaying { 193 | handlePlay(state: true) 194 | } 195 | } 196 | 197 | @IBAction func handleRewindButton(_ sender: NSButton) { 198 | handleRewind() 199 | } 200 | 201 | @IBAction func handlePlayButton(_ sender: NSButton) { 202 | handlePlay(state: sender.state == .on) 203 | } 204 | 205 | @IBAction func chooseAudio(_ sender: Any) { 206 | guard let window = view.window else { return } 207 | AKLog("chooseAudio()") 208 | if openPanel == nil { 209 | openPanel = NSOpenPanel() 210 | openPanel?.appearance = view.appearance 211 | openPanel?.message = "Open Audio File" 212 | openPanel?.allowedFileTypes = EZAudioFile.supportedAudioFileTypes() as? [String] 213 | } 214 | openPanel?.beginSheetModal(for: window, completionHandler: { response in 215 | if response == NSApplication.ModalResponse.OK { 216 | if let url = self.openPanel?.url { 217 | self.open(url: url) 218 | } 219 | } 220 | }) 221 | } 222 | 223 | @IBAction func handleMidiDeviceSelected(_ sender: NSPopUpButton) { 224 | midiManager?.openInput(index: sender.indexOfSelectedItem) 225 | } 226 | 227 | @IBAction func handleInstrumentSelected(_ sender: NSPopUpButton) { 228 | guard let auname = sender.titleOfSelectedItem else { return } 229 | 230 | if auname == "-" { 231 | // dispose the old one? 232 | removeInstrument() 233 | return 234 | } 235 | 236 | internalManager.createInstrument(name: auname, completionHandler: { audioUnit in 237 | guard let audioUnit = audioUnit else { return } 238 | 239 | AKLog("* \(audioUnit.name) : Audio Unit created") 240 | 241 | self.auInstrument = AKAudioUnitInstrument(audioUnit: audioUnit) 242 | 243 | if self.auInstrument == nil { 244 | return 245 | } 246 | self.internalManager.connectEffects(firstNode: self.auInstrument, lastNode: self.mixer) 247 | DispatchQueue.main.async { 248 | self.showAudioUnit(audioUnit, identifier: 6) 249 | self.instrumentPlayButton.isEnabled = true 250 | } 251 | }) 252 | } 253 | 254 | fileprivate func removeInstrument() { 255 | auInstrument?.detach() 256 | auInstrument = nil 257 | instrumentPlayButton.isEnabled = false 258 | getWindowFromIndentifier(6)?.close() 259 | } 260 | 261 | @IBAction func handleShowAudioUnit(_ sender: NSButton) { 262 | let auIndex = sender.tag 263 | AKLog("handleShowAudioUnit() \(auIndex)") 264 | let state = sender.state == .on 265 | showEffect(at: auIndex, state: state) 266 | } 267 | 268 | @IBAction func handleInstrumentPlayButton(_ sender: NSButton) { 269 | guard auInstrument != nil else { return } 270 | 271 | startEngine { 272 | if self.fmOscillator.isStarted { 273 | self.fmButton.state = .off 274 | self.fmOscillator.stop() 275 | } 276 | 277 | if self.player?.isPlaying ?? false { 278 | self.handlePlay(state: false) 279 | } 280 | 281 | if sender.state == .off { 282 | self.testAUInstrument(state: false) 283 | } else { 284 | self.testAUInstrument(state: true) 285 | } 286 | } 287 | } 288 | 289 | @IBAction func handleFMButton(_ sender: NSButton) { 290 | if player?.isPlaying ?? false { 291 | handlePlay(state: false) 292 | } 293 | 294 | if auInstrument != nil { 295 | instrumentPlayButton.state = .off 296 | } 297 | 298 | playFM(state: sender.state == .on) 299 | } 300 | } 301 | 302 | /// Handle Window Events 303 | extension AudioUnitManager: NSWindowDelegate { 304 | func windowWillClose(_ notification: Notification) { 305 | if let w = notification.object as? NSWindow { 306 | if w == view.window { 307 | internalManager.reset() 308 | engine.stop() 309 | exit(0) 310 | } 311 | 312 | if let winId = w.identifier?.rawValue { 313 | // store the location of this window so can reshow at same location 314 | windowPositions[winId] = w.frame.origin 315 | AKLog("\(winId) : Plug in window closing") 316 | 317 | if let tag = Int(winId.replacingOccurrences(of: windowPrefix, with: "")) { 318 | if let b = getEffectsButtonFromIdentifier(tag) { 319 | b.state = .off 320 | } 321 | } 322 | } 323 | } 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitParamSlider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AUParamSlider.swift 3 | // 4 | // Created by Ryan Francesconi, revision history on Githbub. 5 | // Copyright © 2018 AudioKit. All rights reserved. 6 | // 7 | 8 | import AVFoundation 9 | import Cocoa 10 | 11 | class AudioUnitParamSlider: NSView { 12 | private var audioUnit: AVAudioUnit? 13 | private var key: AUParameterAddress? 14 | 15 | private var slider = NSSlider() 16 | private var valueField: NSTextField? 17 | 18 | convenience init(audioUnit: AVAudioUnit, param: AUParameter) { 19 | self.init() 20 | 21 | self.audioUnit = audioUnit 22 | key = param.address 23 | 24 | let titleField = createLabel(string: param.displayName) 25 | titleField.frame = NSRect(x: 0, y: 0, width: 120, height: 20) 26 | addSubview(titleField) 27 | 28 | slider.action = #selector(handleAction(_:)) 29 | slider.target = self 30 | slider.frame = NSRect(x: 122, y: 2, width: 100, height: 20) 31 | addSubview(slider) 32 | 33 | let field = createLabel(string: String(param.value)) 34 | field.alignment = .left 35 | field.frame = NSRect(x: 224, y: 2, width: 28, height: 20) 36 | addSubview(field) 37 | valueField = field 38 | 39 | if let unitName = param.unitName { 40 | let unitsField = createLabel(string: unitName) 41 | unitsField.alignment = .left 42 | unitsField.frame = NSRect(x: 249, y: 2, width: 40, height: 20) 43 | addSubview(unitsField) 44 | } 45 | frame = NSRect(x: 0, y: 0, width: 352, height: 20) 46 | 47 | guard let key = key else { return } 48 | 49 | DispatchQueue.main.async { 50 | // need to refetch the param as it's dispatched later and the reference dies 51 | if let p = self.getParam(withAddress: key) { 52 | self.slider.floatValue = p.value 53 | self.slider.maxValue = Double(p.maxValue) 54 | self.slider.minValue = Double(p.minValue) 55 | self.slider.controlSize = .mini 56 | } 57 | } 58 | } 59 | 60 | // AUParameter references aren't persistent, so we need to refetch them 61 | // addresses aren't guarenteed either, but well... 62 | public func getParam(withAddress theKey: AUParameterAddress) -> AUParameter? { 63 | return audioUnit?.auAudioUnit.parameterTree?.parameter(withAddress: theKey) 64 | } 65 | 66 | private func createLabel(string: String) -> NSTextField { 67 | let tf = NSTextField() 68 | tf.isSelectable = false 69 | tf.isBordered = false 70 | tf.isEditable = false 71 | tf.alignment = .right 72 | tf.font = NSFont.systemFont(ofSize: 8) 73 | tf.textColor = NSColor.white 74 | tf.backgroundColor = NSColor.white.withAlphaComponent(0) 75 | tf.stringValue = string 76 | DispatchQueue.main.async { 77 | tf.controlSize = .mini 78 | } 79 | return tf 80 | } 81 | 82 | @objc func handleAction(_ sender: NSSlider) { 83 | guard sender == slider else { return } 84 | guard let key = key else { return } 85 | 86 | if let p = getParam(withAddress: key) { 87 | // AKLog("p: \(p)") 88 | p.value = slider.floatValue 89 | if let field = valueField { 90 | field.stringValue = "\(round2(slider.floatValue, decimalPlaces: 3))" 91 | } 92 | } 93 | } 94 | 95 | func updateValue() { 96 | guard let key = key else { return } 97 | if let p = getParam(withAddress: key) { 98 | slider.floatValue = p.value 99 | } 100 | } 101 | 102 | private func round2(_ value: Float, decimalPlaces: Int) -> Float { 103 | let decimalValue = pow(10.0, Float(decimalPlaces)) 104 | return round(value * decimalValue) / decimalValue 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitToolbarController.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import AudioKit 4 | import AVFoundation 5 | import Cocoa 6 | 7 | class AudioUnitToolbarController: NSTitlebarAccessoryViewController { 8 | @IBOutlet var bypassButton: NSButton! 9 | 10 | public var audioUnit: AVAudioUnit? 11 | 12 | override func viewDidLoad() { 13 | super.viewDidLoad() 14 | // Do view setup here. 15 | } 16 | 17 | @IBAction func handleBypass(_ sender: NSButton) { 18 | guard let audioUnit = audioUnit else { return } 19 | 20 | let buttonState = bypassButton.state == .on 21 | AKLog("bypass: \(buttonState) audioUnit: \(audioUnit)") 22 | 23 | audioUnit.auAudioUnit.shouldBypassEffect = buttonState 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/AudioUnitToolbarController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/ClosureMenuItem.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | import Cocoa 3 | 4 | /** 5 | Subclassing NSMenuItem to be able to set their actions with closures. 6 | Has the additional upside of settings the targets correctly 7 | */ 8 | class ClosureMenuItem: NSMenuItem { 9 | var actionClosure: () -> Void = {} 10 | 11 | init(title: String, closure: @escaping () -> Void, keyEquivalent: String = "") { 12 | self.actionClosure = closure 13 | super.init(title: title, action: #selector(self.action(_:)), keyEquivalent: keyEquivalent) 14 | self.target = self 15 | } 16 | 17 | required init(coder aDecoder: NSCoder) { // for using view from interface builder / xib 18 | super.init(coder: aDecoder) 19 | } 20 | 21 | @objc func action(_ sender: NSMenuItem) { 22 | self.actionClosure() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/Extensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | 3 | import Cocoa 4 | 5 | extension String { 6 | var digits: String { 7 | return components(separatedBy: CharacterSet.decimalDigits.inverted) 8 | .joined() 9 | } 10 | 11 | func index(from: Int) -> Index { 12 | return self.index(startIndex, offsetBy: from) 13 | } 14 | 15 | func indexOf(string: String) -> String.Index? { 16 | return self.range(of: string, options: .literal, range: nil, locale: nil)?.lowerBound 17 | } 18 | 19 | func trim() -> String { 20 | return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 21 | } 22 | 23 | func toCGFloat() -> CGFloat { 24 | if let n = NumberFormatter().number(from: self) { 25 | let f = CGFloat(truncating: n) 26 | return f 27 | } 28 | return 0.0 29 | } 30 | 31 | func toInt() -> Int { 32 | if let n = NumberFormatter().number(from: self) { 33 | let f = Int(truncating: n) 34 | return f 35 | } 36 | return 0 37 | } 38 | 39 | func toDouble() -> Double { 40 | if let n = NumberFormatter().number(from: self) { 41 | let f = Double(truncating: n) 42 | return f 43 | } 44 | return 0.0 45 | } 46 | 47 | func startsWith(string: String) -> Bool { 48 | guard let range = self.range(of: string, options: [.anchored, .caseInsensitive]) else { 49 | return false 50 | } 51 | 52 | return range.lowerBound == startIndex 53 | } 54 | 55 | func removeSpecial() -> String { 56 | let okayChars = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-_" 57 | return self.filter { okayChars.contains($0) } 58 | } 59 | 60 | func asciiValue() -> [UInt8] { 61 | var retVal = [UInt8]() 62 | for val in self.unicodeScalars where val.isASCII { 63 | retVal.append(UInt8(val.value)) 64 | } 65 | return retVal 66 | } 67 | 68 | public static func toClock(_ time: TimeInterval, frameRate: Float = 0) -> String { 69 | if time.isNaN || time.isInfinite || time.isSignalingNaN { 70 | return String("-") 71 | } 72 | var t = time 73 | var preroll = "" 74 | if time < 0 { 75 | preroll = "-" 76 | } 77 | t = abs(t) 78 | 79 | // calculate the minutes in elapsed time. 80 | let minutes = Int(t / 60.0) 81 | t -= (TimeInterval(minutes) * 60) 82 | 83 | // calculate the seconds in elapsed time. 84 | let seconds = Int(t) 85 | t -= TimeInterval(seconds) 86 | 87 | // find out the fraction of milliseconds to be displayed. 88 | let mult = Double(frameRate > 0 ? frameRate : 100) 89 | let fraction = Int(t * mult) 90 | let strMinutes = String(format: "%02d", minutes) 91 | let strSeconds = String(format: "%02d", seconds) 92 | let strFraction = String(format: "%02d", fraction) 93 | let out = "\(preroll)\(strMinutes):\(strSeconds):\(strFraction)" 94 | return out 95 | } 96 | 97 | public static func toTimecode(frame: Int, fps: Float) -> String { 98 | let ff = Int(Float(frame).truncatingRemainder(dividingBy: fps)) 99 | let seconds = Int(Float(frame - ff) / fps) 100 | let ss = seconds % 60 101 | let mm = (seconds % 3_600) / 60 102 | let timecode = [String(format: "%02d", mm), String(format: "%02d", ss), String(format: "%02d", ff)] 103 | return timecode.joined(separator: ":") 104 | } 105 | 106 | public static func toSimpleClock(_ time: TimeInterval) -> String { 107 | var t = time 108 | var preroll = "" 109 | if time < 0 { 110 | preroll = "-" 111 | } 112 | t = abs(t) 113 | 114 | // calculate the minutes in elapsed time. 115 | let minutes = Int(t / 60.0) 116 | t -= (TimeInterval(minutes) * 60) 117 | 118 | // calculate the seconds in elapsed time. 119 | let seconds = Int(t) 120 | t -= TimeInterval(seconds) 121 | let strSeconds = String(format: "%02d", seconds) 122 | let out = "\(preroll)\(minutes):\(strSeconds)" 123 | return out 124 | } 125 | } 126 | 127 | extension String.Index { 128 | func successor(in string: String) -> String.Index { 129 | return string.index(after: self) 130 | } 131 | 132 | func predecessor(in string: String) -> String.Index { 133 | return string.index(before: self) 134 | } 135 | 136 | func advance(_ offset: Int, for string: String) -> String.Index { 137 | return string.index(self, offsetBy: offset) 138 | } 139 | } 140 | 141 | extension NSLayoutConstraint { 142 | public static func simpleVisualConstraints(view: NSView, 143 | direction: NSString = "H", 144 | padding1: Int = 0, 145 | padding2: Int = 0) -> [NSLayoutConstraint] { 146 | view.translatesAutoresizingMaskIntoConstraints = false 147 | let constraint = NSLayoutConstraint.constraints( 148 | withVisualFormat: "\(direction):|-\(padding1)-[view]-\(padding2)-|", 149 | options: NSLayoutConstraint.FormatOptions(rawValue: 0), 150 | metrics: nil, 151 | views: ["view": view]) 152 | return constraint 153 | } 154 | 155 | public static func activateConstraintsEqualToSuperview(child: NSView) { 156 | guard let superview = child.superview else { 157 | print("NSLayoutConstraint.fillSuperview() superview of child is nil") 158 | return 159 | } 160 | 161 | child.translatesAutoresizingMaskIntoConstraints = false 162 | 163 | NSLayoutConstraint.activate([ 164 | child.leadingAnchor.constraint(equalTo: superview.leadingAnchor), 165 | child.trailingAnchor.constraint(equalTo: superview.trailingAnchor), 166 | child.topAnchor.constraint(equalTo: superview.topAnchor), 167 | child.bottomAnchor.constraint(equalTo: superview.bottomAnchor) 168 | ]) 169 | } 170 | } 171 | 172 | extension NSView { 173 | func convertEventToSuperview(theEvent: NSEvent) -> NSPoint { 174 | let localPoint = self.convert(theEvent.locationInWindow, from: nil) 175 | let svLocation = self.convert(localPoint, to: self.superview) 176 | return svLocation 177 | } 178 | 179 | func convertToSuperview(localPoint: NSPoint) -> NSPoint { 180 | let svLocation = self.convert(localPoint, to: self.superview) 181 | return svLocation 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/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 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSApplicationCategoryType 24 | public.app-category.music 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2017 Ryan Francesconi. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/InstrumentPlayer.swift: -------------------------------------------------------------------------------- 1 | // MARK: - Instrument Player 2 | /* 3 | This class implements a basic player for our instrument sample au, 4 | sending a whole tone scale on a concurrent thread until stopped. 5 | */ 6 | import AVFoundation 7 | import Cocoa 8 | 9 | public class InstrumentPlayer: NSObject { 10 | private let playingQueue = DispatchQueue(label: "InstrumentPlayer.playingQueue") 11 | 12 | private var noteBlock: AUScheduleMIDIEventBlock 13 | 14 | private var _isPlaying: Bool = false 15 | 16 | public var isPlaying: Bool { 17 | get { 18 | var result = false 19 | playingQueue.sync { 20 | result = self._isPlaying 21 | } 22 | return result 23 | } 24 | 25 | set { 26 | self.playingQueue.sync { 27 | self._isPlaying = newValue 28 | } 29 | } 30 | } 31 | 32 | internal init?(audioUnit: AUAudioUnit?) { 33 | guard let audioUnit = audioUnit else { return nil } 34 | guard let theNoteBlock = audioUnit.scheduleMIDIEventBlock else { return nil } 35 | 36 | self.noteBlock = theNoteBlock 37 | super.init() 38 | } 39 | 40 | internal func play() { 41 | if !self.isPlaying { 42 | self.scheduleInstrumentLoop() 43 | } 44 | } 45 | 46 | func stop() { 47 | self.isPlaying = false 48 | } 49 | 50 | private func scheduleInstrumentLoop() { 51 | self.isPlaying = true 52 | 53 | let cbytes = UnsafeMutablePointer.allocate(capacity: 3) 54 | 55 | DispatchQueue.global(qos: .default).async { 56 | cbytes[0] = 0xB0 57 | cbytes[1] = 123 58 | cbytes[2] = 0 59 | self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes) 60 | 61 | usleep(useconds_t(0.1 * 1e6)) 62 | var releaseTime: Float = 0.05 63 | usleep(useconds_t(0.1 * 1e6)) 64 | 65 | var i = 0 66 | while self.isPlaying { 67 | // lengthen the releaseTime by 5% each time up to 10 seconds. 68 | if releaseTime < 10.0 { 69 | releaseTime = min(releaseTime * 1.05, 10.0) 70 | } 71 | 72 | cbytes[0] = 0x90 73 | cbytes[1] = UInt8(60 + i) 74 | cbytes[2] = 64 75 | self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes) 76 | 77 | usleep(useconds_t(0.2 * 1e6)) 78 | 79 | cbytes[2] = 0 // note off 80 | self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes) 81 | 82 | i += 2 83 | if i >= 24 { 84 | i = -12 85 | } 86 | } // while isPlaying 87 | 88 | cbytes[0] = 0xB0 89 | cbytes[1] = 123 90 | cbytes[2] = 0 91 | self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes) 92 | 93 | cbytes.deallocate() 94 | 95 | } // dispached 96 | } // scheduleInstrumentLoop 97 | } 98 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/MenuButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuButton.swift 3 | // AudioUnitManager 4 | // 5 | // Created by Ryan Francesconi, revision history on Githbub. 6 | // 7 | 8 | import Cocoa 9 | 10 | @IBDesignable 11 | class MenuButton: NSButton { 12 | @IBInspectable var bgColor: NSColor? 13 | @IBInspectable var textColor: NSColor? 14 | override func awakeFromNib() { 15 | super.awakeFromNib() 16 | if let textColor = textColor, let font = font { 17 | let style = NSMutableParagraphStyle() 18 | style.alignment = .center 19 | let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: textColor, 20 | NSAttributedString.Key.font: font, 21 | NSAttributedString.Key.paragraphStyle: style] 22 | let attributedTitle = NSAttributedString(string: title, attributes: attributes) 23 | self.attributedTitle = attributedTitle 24 | initialize() 25 | } 26 | } 27 | 28 | override func draw(_ dirtyRect: NSRect) { 29 | if let bgColor = bgColor { 30 | bgColor.setFill() 31 | let rect = NSRect(origin: CGPoint(), size: bounds.size) 32 | let rectanglePath = NSBezierPath(roundedRect: rect, xRadius: 3, yRadius: 3) 33 | rectanglePath.fill() 34 | } 35 | super.draw(dirtyRect) 36 | } 37 | 38 | override init(frame frameRect: NSRect) { 39 | super.init(frame: frameRect) 40 | initialize() 41 | } 42 | 43 | required init?(coder: NSCoder) { 44 | super.init(coder: coder) 45 | initialize() 46 | } 47 | 48 | private func initialize() { 49 | if let cell = self.cell as? NSButtonCell { 50 | cell.isBordered = false // The background color is used only when drawing borderless buttons. 51 | // cell.backgroundColor = bgColor //NSColor.gray.withAlphaComponent(0.5) 52 | } 53 | } 54 | 55 | override func rightMouseDown(with event: NSEvent) { 56 | // kill this 57 | } 58 | 59 | override func mouseDown(with event: NSEvent) { 60 | guard isEnabled else { return } 61 | guard let menu = menu else { return } 62 | 63 | var adjustedLocation = convert(NSPoint(), to: nil) 64 | adjustedLocation.y -= (frame.size.height + 5) 65 | if let newEvent = NSEvent.mouseEvent(with: event.type, 66 | location: adjustedLocation, 67 | modifierFlags: event.modifierFlags, 68 | timestamp: event.timestamp, 69 | windowNumber: event.windowNumber, 70 | context: nil, 71 | eventNumber: event.eventNumber + 1, 72 | clickCount: 1, 73 | pressure: 0) { 74 | menu.autoenablesItems = false 75 | NSMenu.popUpContextMenu(menu, with: newEvent, for: self) 76 | } 77 | } 78 | 79 | override func mouseUp(with event: NSEvent) { 80 | super.mouseUp(with: event) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /macOS/AudioUnitManager/WaveformView.swift: -------------------------------------------------------------------------------- 1 | // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/ 2 | import AudioKit 3 | import AppKit 4 | 5 | /// This is a demo of an Audio Region class. Not for production use... ;) 6 | public class WaveformView: AKView { 7 | public var url: URL? 8 | public var plots = [AKWaveformLayer?]() 9 | public var file: EZAudioFile? 10 | public var visualScaleFactor: Double = 30 11 | public var color = NSColor.black 12 | public weak var delegate: WaveformViewDelegate? 13 | private var loopStartMarker = LoopMarker(.start) 14 | private var loopEndMarker = LoopMarker(.end) 15 | 16 | private var basicShadow: NSShadow { 17 | let shadow = NSShadow() 18 | shadow.shadowBlurRadius = 5 19 | shadow.shadowOffset = CGSize(width: 2, height: -2) 20 | shadow.shadowColor = NSColor.black.withAlphaComponent(0.7) 21 | return shadow 22 | } 23 | 24 | public var displayTimebar: Bool = true { 25 | didSet { 26 | timelineBar.isHidden = !displayTimebar 27 | } 28 | } 29 | 30 | private var timelineBar = TimelineBar() 31 | 32 | /// position in seconds of the bar 33 | public var position: Double { 34 | get { 35 | return Double(timelineBar.frame.origin.x) / visualScaleFactor 36 | } 37 | 38 | set { 39 | timelineBar.frame.origin.x = CGFloat(newValue * visualScaleFactor) 40 | } 41 | } 42 | 43 | public var loopStart: Double { 44 | get { 45 | return Double(loopStartMarker.frame.origin.x) / visualScaleFactor 46 | } 47 | 48 | set { 49 | loopStartMarker.frame.origin.x = CGFloat(newValue * visualScaleFactor) 50 | } 51 | } 52 | 53 | public var loopEnd: Double { 54 | get { 55 | return Double(loopEndMarker.frame.origin.x + loopEndMarker.frame.width) / visualScaleFactor 56 | } 57 | 58 | set { 59 | loopEndMarker.frame.origin.x = CGFloat(newValue * visualScaleFactor) - loopEndMarker.frame.width 60 | } 61 | } 62 | 63 | public var isLooping: Bool = false { 64 | didSet { 65 | loopStartMarker.isHidden = !isLooping 66 | loopEndMarker.isHidden = !isLooping 67 | needsDisplay = true 68 | } 69 | } 70 | 71 | public var isReversed: Bool = false { 72 | didSet { 73 | for plot in plots { 74 | if isReversed { 75 | plot?.transform = CATransform3DMakeRotation(CGFloat(Double.pi), 0, 1, 0) 76 | } else { 77 | // To flip back to normal 78 | plot?.transform = CATransform3DMakeRotation(0, 0, 1, 0) 79 | } 80 | } 81 | } 82 | } 83 | 84 | convenience init?(url: URL, color: NSColor = NSColor.white) { 85 | self.init() 86 | file = EZAudioFile(url: url) 87 | self.color = color 88 | if file == nil { return nil } 89 | initialize() 90 | } 91 | 92 | private func initialize() { 93 | wantsLayer = true 94 | layer = CALayer() 95 | 96 | frame = NSRect(x: 0, y: 0, width: 200, height: 20) 97 | 98 | guard let file = file else { return } 99 | guard let data = getFloatChannelData(withNumberOfPoints: 256) else { return } 100 | guard let leftData = data.first else { return } 101 | 102 | let leftPlot = createPlot(data: leftData) 103 | layer?.addSublayer(leftPlot) 104 | plots.insert(leftPlot, at: 0) 105 | 106 | // if the file is stereo add a second plot for the right channel 107 | if file.fileFormat.mChannelsPerFrame > 1, let rightData = data.last { 108 | let rightPlot = createPlot(data: rightData) 109 | layer?.addSublayer(rightPlot) 110 | plots.insert(rightPlot, at: 1) 111 | } 112 | loopStartMarker.delegate = self 113 | loopEndMarker.delegate = self 114 | addSubview(loopStartMarker) 115 | addSubview(loopEndMarker) 116 | addSubview(timelineBar) 117 | timelineBar.shadow = basicShadow 118 | isLooping = false 119 | } 120 | 121 | public func getFloatChannelData(withNumberOfPoints: Int) -> [[Float]]? { 122 | guard let file = file, 123 | let data = file.getWaveformData(withNumberOfPoints: UInt32(withNumberOfPoints)), 124 | let buffers = data.buffers else { 125 | return nil 126 | } 127 | var output = [[Float]]() 128 | 129 | // this makes a copy which isn't ideal 130 | if let leftData = buffers[0] { 131 | let leftBuffer = UnsafeBufferPointer(start: leftData, count: withNumberOfPoints) 132 | let floatBuffer = [Float](leftBuffer) 133 | output.append([Float](floatBuffer)) 134 | } 135 | 136 | if file.fileFormat.mChannelsPerFrame > 1, let rightData = buffers[1] { 137 | let rightBuffer = UnsafeBufferPointer(start: rightData, count: withNumberOfPoints) 138 | let floatBuffer = [Float](rightBuffer) 139 | output.append(floatBuffer) 140 | } 141 | return output 142 | } 143 | 144 | private func createPlot(data: [Float]) -> AKWaveformLayer { 145 | let plot = AKWaveformLayer(table: data, 146 | size: nil, 147 | fillColor: color.cgColor, 148 | strokeColor: nil, 149 | backgroundColor: nil, 150 | opacity: 1, 151 | isMirrored: true) 152 | 153 | // add a shadow 154 | plot.shadowColor = NSColor.black.cgColor 155 | plot.shadowOpacity = 0.4 156 | plot.shadowOffset = NSSize(width: 1, height: -1) 157 | plot.shadowRadius = 2.0 158 | 159 | return plot 160 | } 161 | 162 | public override func draw(_ dirtyRect: NSRect) { 163 | super.draw(dirtyRect) 164 | 165 | guard isLooping else { return } 166 | let loopShading = NSRect(x: loopStartMarker.frame.origin.x, 167 | y: 0, 168 | width: loopEndMarker.frame.origin.x - loopStartMarker.frame.origin.x + 169 | loopEndMarker.frame.width, 170 | height: frame.height) 171 | let rectanglePath = NSBezierPath(rect: loopShading) 172 | let color = NSColor(calibratedRed: 0.975, green: 0.823, blue: 0.573, alpha: 0.328) 173 | color.setFill() 174 | rectanglePath.fill() 175 | } 176 | 177 | public func fitToFrame() { 178 | guard let file = file, file.duration != 0 else { return } 179 | let w = Double(frame.width) 180 | let scale = w / file.duration 181 | visualScaleFactor = scale 182 | loopEndMarker.frame.origin.x = frame.width - loopEndMarker.frame.width - 3 183 | } 184 | 185 | public override func setFrameSize(_ newSize: NSSize) { 186 | guard let file = file else { return } 187 | guard !plots.isEmpty else { return } 188 | 189 | super.setFrameSize(newSize) 190 | 191 | let channels = CGFloat(file.fileFormat.mChannelsPerFrame) 192 | let waveformSize = NSSize(width: newSize.width, height: (newSize.height / channels) - 2) 193 | 194 | plots.first??.frame.origin = NSPoint(x: 0, y: channels == 1 ? 0 : newSize.height / channels) 195 | plots.first??.updateLayer(with: waveformSize) 196 | 197 | if channels > 1 { 198 | plots.last??.frame.origin = NSPoint() 199 | plots.last??.updateLayer(with: waveformSize) 200 | } 201 | } 202 | 203 | public override func mouseDown(with event: NSEvent) { 204 | super.mouseDown(with: event) 205 | position = mousePositionToTime(with: event) 206 | delegate?.waveformSelected(source: self, at: position) 207 | } 208 | 209 | public override func mouseUp(with event: NSEvent) { 210 | super.mouseUp(with: event) 211 | delegate?.waveformScrubComplete(source: self, at: position) 212 | } 213 | 214 | public override func mouseDragged(with event: NSEvent) { 215 | position = mousePositionToTime(with: event) 216 | delegate?.waveformScrubbed(source: self, at: position) 217 | needsDisplay = true 218 | } 219 | 220 | private func mousePositionToTime(with event: NSEvent) -> Double { 221 | guard let file = file else { return 0 } 222 | 223 | let loc = convert(event.locationInWindow, from: nil) 224 | let mouseTime = Double(loc.x / frame.width) * file.duration 225 | return mouseTime 226 | } 227 | 228 | public func dispose() { 229 | file = nil 230 | plots.removeAll() 231 | removeFromSuperview() 232 | } 233 | } 234 | 235 | extension WaveformView: LoopMarkerDelegate { 236 | func markerMoved(source: LoopMarker) { 237 | if source.loopType == .start { 238 | source.frame.origin.x = max(0, source.frame.origin.x) 239 | source.frame.origin.x = min(source.frame.origin.x, loopEndMarker.frame.origin.x - loopEndMarker.frame.width) 240 | } else if source.loopType == .end { 241 | source.frame.origin.x = max(loopStartMarker.frame.origin.x + loopStartMarker.frame.width, 242 | source.frame.origin.x) 243 | source.frame.origin.x = min(source.frame.origin.x, frame.width - source.frame.width - 3) 244 | } 245 | needsDisplay = true 246 | delegate?.loopChanged(source: self) 247 | } 248 | } 249 | 250 | public protocol WaveformViewDelegate: class { 251 | func waveformSelected(source: WaveformView, at time: Double) 252 | func waveformScrubbed(source: WaveformView, at time: Double) 253 | func waveformScrubComplete(source: WaveformView, at time: Double) 254 | func loopChanged(source: WaveformView) 255 | } 256 | 257 | /// Class to show looping bounds on top of the waveform 258 | class LoopMarker: AKView { 259 | public enum MarkerType { 260 | case start, end 261 | } 262 | 263 | public weak var delegate: LoopMarkerDelegate? 264 | public var loopType: MarkerType = .start 265 | private var mouseDownLocation: NSPoint? 266 | 267 | convenience init(_ loopType: MarkerType) { 268 | self.init(frame: NSRect(x: 0, y: 0, width: 5, height: 70)) 269 | self.loopType = loopType 270 | } 271 | 272 | public func fitToFrame() { 273 | guard let superview = superview else { return } 274 | frame = NSRect(x: 0, y: 0, width: 6, height: superview.frame.height - 2) 275 | needsDisplay = true 276 | } 277 | 278 | override func draw(_ dirtyRect: NSRect) { 279 | if loopType == .start { 280 | drawStartRepeat() 281 | } else if loopType == .end { 282 | drawEndRepeat() 283 | } 284 | } 285 | 286 | fileprivate func drawStartRepeat() { 287 | NSColor.black.setFill() 288 | let rectanglePath = NSBezierPath(rect: NSRect(x: 0, y: 0, width: 2, height: 66)) 289 | rectanglePath.fill() 290 | 291 | let rectangle2Path = NSBezierPath(rect: NSRect(x: 0, y: 66, width: 5, height: 2)) 292 | rectangle2Path.fill() 293 | 294 | let rectangle3Path = NSBezierPath(rect: NSRect(x: 0, y: 0, width: 5, height: 2)) 295 | rectangle3Path.fill() 296 | } 297 | 298 | fileprivate func drawEndRepeat() { 299 | NSColor.black.setFill() 300 | let rectanglePath = NSBezierPath(rect: NSRect(x: 3, y: 0, width: 2, height: 66)) 301 | rectanglePath.fill() 302 | 303 | let rectangle2Path = NSBezierPath(rect: NSRect(x: 0, y: 66, width: 5, height: 2)) 304 | rectangle2Path.fill() 305 | 306 | let rectangle3Path = NSBezierPath(rect: NSRect(x: 0, y: 0, width: 5, height: 2)) 307 | rectangle3Path.fill() 308 | } 309 | 310 | override func mouseDown(with event: NSEvent) { 311 | super.mouseDown(with: event) 312 | mouseDownLocation = convert(event.locationInWindow, from: nil) 313 | } 314 | 315 | override func mouseDragged(with event: NSEvent) { 316 | super.mouseDragged(with: event) 317 | guard let mouseDownLocation = mouseDownLocation else { return } 318 | 319 | let svLocation = convertEventToSuperview(theEvent: event) 320 | let pt = CGPoint(x: svLocation.x - mouseDownLocation.x, y: 0) 321 | setFrameOrigin(pt) 322 | } 323 | 324 | override func mouseUp(with event: NSEvent) { 325 | super.mouseUp(with: event) 326 | guard superview != nil else { return } 327 | delegate?.markerMoved(source: self) 328 | } 329 | 330 | deinit { 331 | AKLog("* deinit AKWaveform") 332 | } 333 | } 334 | 335 | protocol LoopMarkerDelegate: class { 336 | func markerMoved(source: LoopMarker) 337 | } 338 | 339 | class TimelineBar: AKView { 340 | private let color = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) 341 | private var rect = NSRect(x: 0, y: 0, width: 2, height: 70) 342 | 343 | convenience init() { 344 | self.init(frame: NSRect(x: 0, y: 0, width: 2, height: 70)) 345 | wantsLayer = true 346 | } 347 | 348 | public func updateSize(height: CGFloat = 0) { 349 | guard let superview = superview else { return } 350 | let theHeight = height > 0 ? height : superview.frame.height 351 | setFrameSize(NSSize(width: 2, height: theHeight)) 352 | rect = NSRect(x: 0, y: 0, width: 2, height: bounds.height) 353 | needsDisplay = true 354 | } 355 | 356 | override func draw(_ dirtyRect: NSRect) { 357 | if let context = NSGraphicsContext.current { 358 | context.shouldAntialias = false 359 | } 360 | color.setFill() 361 | rect.fill() 362 | } 363 | } 364 | --------------------------------------------------------------------------------