[
  {
    "path": ".github/pull_request_template.md",
    "content": "NOTE: - While you can open new pull requests WE ADVISE AGAINST IT and as such our response may be limited.\n\nThis project doesn't accept pull requests. Opening an issue is the recommended method to report a bug or provide feedback. You can also fork the repo if you wish to customize it. If you want to open a pull request anyway, please review [CONTRIBUTING.md](../CONTRIBUTING.md) first and indicate your agreement to the terms outlined in CONTRIBUTING.md by checking the box below.\n\nWe appreciate your interest in the project!\n\nDo not erase the below when submitting your pull request:\n#########\n\n- [ ] I understand that response time may be limited because the project doesn't accept pull requests.\n- [ ] I agree to the terms outlined in CONTRIBUTING.md \n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.cache/\nxcuserdata/\n"
  },
  {
    "path": "AudioUnitSDK.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t394A97042576BF1700897571 /* AUMIDIUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 394A97032576BF1700897571 /* AUMIDIUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t64339772294B5DDC00DCD59F /* AUThreadSafeListTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 64339771294B5DDC00DCD59F /* AUThreadSafeListTests.mm */; };\n\t\t643D7987292BF34C00910294 /* AUThreadSafeList.h in Headers */ = {isa = PBXBuildFile; fileRef = 643D7986292BF34C00910294 /* AUThreadSafeList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100832E24DF0EB6003E57AE /* AUInputElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC75924D9181600725ABE /* AUInputElement.cpp */; };\n\t\t9100832F24DF0EE7003E57AE /* AUOutputElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC75824D9181600725ABE /* AUOutputElement.cpp */; };\n\t\t9100833024DF0F2C003E57AE /* AUBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC76224D9181600725ABE /* AUBase.cpp */; };\n\t\t9100833D24DF1CCC003E57AE /* EmptyPlugIns.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9100833C24DF1CCC003E57AE /* EmptyPlugIns.cpp */; };\n\t\t9100834124DF1EEB003E57AE /* libAudioUnitSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 910C29CE24D910D300B9116B /* libAudioUnitSDK.a */; };\n\t\t9100834324DF1EF5003E57AE /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9100834224DF1EF5003E57AE /* AudioToolbox.framework */; };\n\t\t9100835124DF3D54003E57AE /* AUEffectBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9100834F24DF3245003E57AE /* AUEffectBase.cpp */; };\n\t\t9100835424DF4125003E57AE /* AUMIDIBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9100834E24DF3245003E57AE /* AUMIDIBase.cpp */; };\n\t\t9100835524DF421A003E57AE /* MusicDeviceBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9100834624DF3245003E57AE /* MusicDeviceBase.cpp */; };\n\t\t9100835724DF9BAC003E57AE /* AUMIDIEffectBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9100834C24DF3245003E57AE /* AUMIDIEffectBase.cpp */; };\n\t\t9100835824E05892003E57AE /* AUScopeElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC75C24D9181600725ABE /* AUScopeElement.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835924E05892003E57AE /* AUSilentTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100835224DF3DAC003E57AE /* AUSilentTimeout.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835A24E05892003E57AE /* AUInputElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC76024D9181600725ABE /* AUInputElement.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835B24E05892003E57AE /* AUMIDIEffectBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100834524DF3245003E57AE /* AUMIDIEffectBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835C24E05892003E57AE /* AUPlugInDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC75F24D9181600725ABE /* AUPlugInDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835D24E05892003E57AE /* AUMIDIBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100834424DF3245003E57AE /* AUMIDIBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835E24E05892003E57AE /* AUOutputElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC75B24D9181600725ABE /* AUOutputElement.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100835F24E05892003E57AE /* AUEffectBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100834924DF3245003E57AE /* AUEffectBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100836024E05892003E57AE /* MusicDeviceBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100834B24DF3245003E57AE /* MusicDeviceBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100836124E05892003E57AE /* AUUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 9100832D24DF0C5B003E57AE /* AUUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t9100836224E05892003E57AE /* AUBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC76124D9181600725ABE /* AUBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t910C29D824D9115100B9116B /* ComponentBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 910C29D624D9115100B9116B /* ComponentBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t910C29D924D9115100B9116B /* ComponentBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 910C29D724D9115100B9116B /* ComponentBase.cpp */; };\n\t\t914EC77424D91FFA00725ABE /* AUPlugInDispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC77324D91FFA00725ABE /* AUPlugInDispatch.cpp */; };\n\t\t914EC77824D920CC00725ABE /* AUBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC77624D920CC00725ABE /* AUBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t914EC77B24D9225800725ABE /* AudioUnitSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 914EC77A24D9225800725ABE /* AudioUnitSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t914EC77D24D9D91A00725ABE /* AUBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC77524D920CC00725ABE /* AUBuffer.cpp */; };\n\t\t914EC77E24D9DB3800725ABE /* AUScopeElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914EC75D24D9181600725ABE /* AUScopeElement.cpp */; };\n\t\t915DA08024E32B37007C6B53 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 915DA07F24E32B37007C6B53 /* CoreFoundation.framework */; };\n\t\t91850A902CFA37FC005F9E2F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9100834224DF1EF5003E57AE /* AudioToolbox.framework */; };\n\t\t919B0CC62555C72000C59BDC /* AUBufferAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B0CC42555C72000C59BDC /* AUBufferAllocator.cpp */; };\n\t\t91E93AC324E8962D00BF7289 /* Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91E93AC224E8962D00BF7289 /* Tests.mm */; };\n\t\t91E93AC524E8962D00BF7289 /* libAudioUnitSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 910C29CE24D910D300B9116B /* libAudioUnitSDK.a */; };\n\t\tB49E353A29E8039C0093D6B7 /* AUConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = B49E353929E8039C0093D6B7 /* AUConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t9100833E24DF1DEF003E57AE /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 910C29C624D910D300B9116B /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 910C29CD24D910D300B9116B;\n\t\t\tremoteInfo = AudioUnitSDK;\n\t\t};\n\t\t91E93AC624E8962D00BF7289 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 910C29C624D910D300B9116B /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 910C29CD24D910D300B9116B;\n\t\t\tremoteInfo = AudioUnitSDK;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t394A97032576BF1700897571 /* AUMIDIUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUMIDIUtility.h; sourceTree = \"<group>\"; };\n\t\t64339771294B5DDC00DCD59F /* AUThreadSafeListTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AUThreadSafeListTests.mm; sourceTree = \"<group>\"; };\n\t\t643D7986292BF34C00910294 /* AUThreadSafeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUThreadSafeList.h; sourceTree = \"<group>\"; };\n\t\t9100832D24DF0C5B003E57AE /* AUUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUUtility.h; sourceTree = \"<group>\"; };\n\t\t9100833524DF1C82003E57AE /* EmptyPlugIns.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EmptyPlugIns.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t9100833724DF1C82003E57AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t9100833C24DF1CCC003E57AE /* EmptyPlugIns.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = EmptyPlugIns.cpp; sourceTree = \"<group>\"; };\n\t\t9100834224DF1EF5003E57AE /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };\n\t\t9100834424DF3245003E57AE /* AUMIDIBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUMIDIBase.h; sourceTree = \"<group>\"; };\n\t\t9100834524DF3245003E57AE /* AUMIDIEffectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUMIDIEffectBase.h; sourceTree = \"<group>\"; };\n\t\t9100834624DF3245003E57AE /* MusicDeviceBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MusicDeviceBase.cpp; sourceTree = \"<group>\"; };\n\t\t9100834924DF3245003E57AE /* AUEffectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUEffectBase.h; sourceTree = \"<group>\"; };\n\t\t9100834B24DF3245003E57AE /* MusicDeviceBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicDeviceBase.h; sourceTree = \"<group>\"; };\n\t\t9100834C24DF3245003E57AE /* AUMIDIEffectBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AUMIDIEffectBase.cpp; sourceTree = \"<group>\"; };\n\t\t9100834E24DF3245003E57AE /* AUMIDIBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AUMIDIBase.cpp; sourceTree = \"<group>\"; };\n\t\t9100834F24DF3245003E57AE /* AUEffectBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AUEffectBase.cpp; sourceTree = \"<group>\"; };\n\t\t9100835224DF3DAC003E57AE /* AUSilentTimeout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUSilentTimeout.h; sourceTree = \"<group>\"; };\n\t\t9100837424E06BA7003E57AE /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = \"<group>\"; };\n\t\t910C29CE24D910D300B9116B /* libAudioUnitSDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAudioUnitSDK.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t910C29D624D9115100B9116B /* ComponentBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComponentBase.h; sourceTree = \"<group>\"; };\n\t\t910C29D724D9115100B9116B /* ComponentBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComponentBase.cpp; sourceTree = \"<group>\"; };\n\t\t914EC75824D9181600725ABE /* AUOutputElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUOutputElement.cpp; sourceTree = \"<group>\"; };\n\t\t914EC75924D9181600725ABE /* AUInputElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUInputElement.cpp; sourceTree = \"<group>\"; };\n\t\t914EC75B24D9181600725ABE /* AUOutputElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUOutputElement.h; sourceTree = \"<group>\"; };\n\t\t914EC75C24D9181600725ABE /* AUScopeElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUScopeElement.h; sourceTree = \"<group>\"; };\n\t\t914EC75D24D9181600725ABE /* AUScopeElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUScopeElement.cpp; sourceTree = \"<group>\"; };\n\t\t914EC75F24D9181600725ABE /* AUPlugInDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUPlugInDispatch.h; sourceTree = \"<group>\"; };\n\t\t914EC76024D9181600725ABE /* AUInputElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUInputElement.h; sourceTree = \"<group>\"; };\n\t\t914EC76124D9181600725ABE /* AUBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUBase.h; sourceTree = \"<group>\"; };\n\t\t914EC76224D9181600725ABE /* AUBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUBase.cpp; sourceTree = \"<group>\"; };\n\t\t914EC77324D91FFA00725ABE /* AUPlugInDispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUPlugInDispatch.cpp; sourceTree = \"<group>\"; };\n\t\t914EC77524D920CC00725ABE /* AUBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AUBuffer.cpp; sourceTree = \"<group>\"; };\n\t\t914EC77624D920CC00725ABE /* AUBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUBuffer.h; sourceTree = \"<group>\"; };\n\t\t914EC77A24D9225800725ABE /* AudioUnitSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioUnitSDK.h; sourceTree = \"<group>\"; };\n\t\t915DA07F24E32B37007C6B53 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };\n\t\t919B0CC42555C72000C59BDC /* AUBufferAllocator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AUBufferAllocator.cpp; sourceTree = \"<group>\"; };\n\t\t91E93AC024E8962D00BF7289 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t91E93AC224E8962D00BF7289 /* Tests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Tests.mm; sourceTree = \"<group>\"; };\n\t\t91E93AC424E8962D00BF7289 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tB49E353929E8039C0093D6B7 /* AUConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AUConfig.h; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t9100833224DF1C82003E57AE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9100834324DF1EF5003E57AE /* AudioToolbox.framework in Frameworks */,\n\t\t\t\t915DA08024E32B37007C6B53 /* CoreFoundation.framework in Frameworks */,\n\t\t\t\t9100834124DF1EEB003E57AE /* libAudioUnitSDK.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t910C29CC24D910D300B9116B /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t91E93ABD24E8962D00BF7289 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t91850A902CFA37FC005F9E2F /* AudioToolbox.framework in Frameworks */,\n\t\t\t\t91E93AC524E8962D00BF7289 /* libAudioUnitSDK.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t9100833624DF1C82003E57AE /* EmptyPlugIns */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9100833724DF1C82003E57AE /* Info.plist */,\n\t\t\t\t9100833C24DF1CCC003E57AE /* EmptyPlugIns.cpp */,\n\t\t\t);\n\t\t\tpath = EmptyPlugIns;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9100834024DF1EEB003E57AE /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9100834224DF1EF5003E57AE /* AudioToolbox.framework */,\n\t\t\t\t915DA07F24E32B37007C6B53 /* CoreFoundation.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9100837324E06B8F003E57AE /* tools */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9100837424E06BA7003E57AE /* build.sh */,\n\t\t\t);\n\t\t\tpath = tools;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t910C29C524D910D300B9116B = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB487F106284500520074F0B2 /* include */,\n\t\t\t\tB487F108284500630074F0B2 /* src */,\n\t\t\t\t9100837324E06B8F003E57AE /* tools */,\n\t\t\t\tB487F109284501700074F0B2 /* demos */,\n\t\t\t\t91E93AC124E8962D00BF7289 /* tests */,\n\t\t\t\t910C29CF24D910D300B9116B /* Products */,\n\t\t\t\t9100834024DF1EEB003E57AE /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t910C29CF24D910D300B9116B /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t910C29CE24D910D300B9116B /* libAudioUnitSDK.a */,\n\t\t\t\t9100833524DF1C82003E57AE /* EmptyPlugIns.bundle */,\n\t\t\t\t91E93AC024E8962D00BF7289 /* Tests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t91E93AC124E8962D00BF7289 /* tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t64339771294B5DDC00DCD59F /* AUThreadSafeListTests.mm */,\n\t\t\t\t91E93AC224E8962D00BF7289 /* Tests.mm */,\n\t\t\t\t91E93AC424E8962D00BF7289 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB487F106284500520074F0B2 /* include */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB4888687282AC1D800521D1A /* AudioUnitSDK */,\n\t\t\t);\n\t\t\tpath = include;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB487F108284500630074F0B2 /* src */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB48885E4282A6D6D00521D1A /* AudioUnitSDK */,\n\t\t\t);\n\t\t\tpath = src;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB487F109284501700074F0B2 /* demos */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9100833624DF1C82003E57AE /* EmptyPlugIns */,\n\t\t\t);\n\t\t\tpath = demos;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB48885E4282A6D6D00521D1A /* AudioUnitSDK */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t914EC76224D9181600725ABE /* AUBase.cpp */,\n\t\t\t\t914EC77524D920CC00725ABE /* AUBuffer.cpp */,\n\t\t\t\t919B0CC42555C72000C59BDC /* AUBufferAllocator.cpp */,\n\t\t\t\t9100834F24DF3245003E57AE /* AUEffectBase.cpp */,\n\t\t\t\t914EC75924D9181600725ABE /* AUInputElement.cpp */,\n\t\t\t\t9100834E24DF3245003E57AE /* AUMIDIBase.cpp */,\n\t\t\t\t9100834C24DF3245003E57AE /* AUMIDIEffectBase.cpp */,\n\t\t\t\t914EC75824D9181600725ABE /* AUOutputElement.cpp */,\n\t\t\t\t914EC77324D91FFA00725ABE /* AUPlugInDispatch.cpp */,\n\t\t\t\t914EC75D24D9181600725ABE /* AUScopeElement.cpp */,\n\t\t\t\t910C29D724D9115100B9116B /* ComponentBase.cpp */,\n\t\t\t\t9100834624DF3245003E57AE /* MusicDeviceBase.cpp */,\n\t\t\t);\n\t\t\tpath = AudioUnitSDK;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB4888687282AC1D800521D1A /* AudioUnitSDK */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49E353929E8039C0093D6B7 /* AUConfig.h */,\n\t\t\t\t914EC76124D9181600725ABE /* AUBase.h */,\n\t\t\t\t914EC77624D920CC00725ABE /* AUBuffer.h */,\n\t\t\t\t914EC77A24D9225800725ABE /* AudioUnitSDK.h */,\n\t\t\t\t9100834924DF3245003E57AE /* AUEffectBase.h */,\n\t\t\t\t914EC76024D9181600725ABE /* AUInputElement.h */,\n\t\t\t\t9100834424DF3245003E57AE /* AUMIDIBase.h */,\n\t\t\t\t9100834524DF3245003E57AE /* AUMIDIEffectBase.h */,\n\t\t\t\t394A97032576BF1700897571 /* AUMIDIUtility.h */,\n\t\t\t\t914EC75B24D9181600725ABE /* AUOutputElement.h */,\n\t\t\t\t914EC75F24D9181600725ABE /* AUPlugInDispatch.h */,\n\t\t\t\t914EC75C24D9181600725ABE /* AUScopeElement.h */,\n\t\t\t\t9100835224DF3DAC003E57AE /* AUSilentTimeout.h */,\n\t\t\t\t643D7986292BF34C00910294 /* AUThreadSafeList.h */,\n\t\t\t\t9100832D24DF0C5B003E57AE /* AUUtility.h */,\n\t\t\t\t910C29D624D9115100B9116B /* ComponentBase.h */,\n\t\t\t\t9100834B24DF3245003E57AE /* MusicDeviceBase.h */,\n\t\t\t);\n\t\t\tpath = AudioUnitSDK;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t910C29CA24D910D300B9116B /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB49E353A29E8039C0093D6B7 /* AUConfig.h in Headers */,\n\t\t\t\t9100836224E05892003E57AE /* AUBase.h in Headers */,\n\t\t\t\t914EC77824D920CC00725ABE /* AUBuffer.h in Headers */,\n\t\t\t\t914EC77B24D9225800725ABE /* AudioUnitSDK.h in Headers */,\n\t\t\t\t9100835F24E05892003E57AE /* AUEffectBase.h in Headers */,\n\t\t\t\t9100835A24E05892003E57AE /* AUInputElement.h in Headers */,\n\t\t\t\t9100835D24E05892003E57AE /* AUMIDIBase.h in Headers */,\n\t\t\t\t9100835B24E05892003E57AE /* AUMIDIEffectBase.h in Headers */,\n\t\t\t\t9100835E24E05892003E57AE /* AUOutputElement.h in Headers */,\n\t\t\t\t9100835C24E05892003E57AE /* AUPlugInDispatch.h in Headers */,\n\t\t\t\t394A97042576BF1700897571 /* AUMIDIUtility.h in Headers */,\n\t\t\t\t9100835824E05892003E57AE /* AUScopeElement.h in Headers */,\n\t\t\t\t9100835924E05892003E57AE /* AUSilentTimeout.h in Headers */,\n\t\t\t\t643D7987292BF34C00910294 /* AUThreadSafeList.h in Headers */,\n\t\t\t\t9100836124E05892003E57AE /* AUUtility.h in Headers */,\n\t\t\t\t910C29D824D9115100B9116B /* ComponentBase.h in Headers */,\n\t\t\t\t9100836024E05892003E57AE /* MusicDeviceBase.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t9100833424DF1C82003E57AE /* EmptyPlugIns */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 9100833824DF1C82003E57AE /* Build configuration list for PBXNativeTarget \"EmptyPlugIns\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t9100833124DF1C82003E57AE /* Sources */,\n\t\t\t\t9100833224DF1C82003E57AE /* Frameworks */,\n\t\t\t\t9100833324DF1C82003E57AE /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t9100833F24DF1DEF003E57AE /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = EmptyPlugIns;\n\t\t\tproductName = EmptyPlugIns;\n\t\t\tproductReference = 9100833524DF1C82003E57AE /* EmptyPlugIns.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n\t\t910C29CD24D910D300B9116B /* AudioUnitSDK */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 910C29D224D910D300B9116B /* Build configuration list for PBXNativeTarget \"AudioUnitSDK\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t9100837924E1A54B003E57AE /* Install clang-format hook */,\n\t\t\t\t910C29CA24D910D300B9116B /* Headers */,\n\t\t\t\t910C29CB24D910D300B9116B /* Sources */,\n\t\t\t\t910C29CC24D910D300B9116B /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AudioUnitSDK;\n\t\t\tproductName = AudioUnitSDK;\n\t\t\tproductReference = 910C29CE24D910D300B9116B /* libAudioUnitSDK.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\t91E93ABF24E8962D00BF7289 /* Tests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 91E93ACA24E8962D00BF7289 /* Build configuration list for PBXNativeTarget \"Tests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t91E93ABC24E8962D00BF7289 /* Sources */,\n\t\t\t\t91E93ABD24E8962D00BF7289 /* Frameworks */,\n\t\t\t\t91E93ABE24E8962D00BF7289 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t91E93AC724E8962D00BF7289 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Tests;\n\t\t\tproductName = Tests;\n\t\t\tproductReference = 91E93AC024E8962D00BF7289 /* Tests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t910C29C624D910D300B9116B /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t9100833424DF1C82003E57AE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.0;\n\t\t\t\t\t};\n\t\t\t\t\t910C29CD24D910D300B9116B = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.0;\n\t\t\t\t\t};\n\t\t\t\t\t91E93ABF24E8962D00BF7289 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 910C29C924D910D300B9116B /* Build configuration list for PBXProject \"AudioUnitSDK\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 910C29C524D910D300B9116B;\n\t\t\tproductRefGroup = 910C29CF24D910D300B9116B /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t910C29CD24D910D300B9116B /* AudioUnitSDK */,\n\t\t\t\t9100833424DF1C82003E57AE /* EmptyPlugIns */,\n\t\t\t\t91E93ABF24E8962D00BF7289 /* Tests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t9100833324DF1C82003E57AE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t91E93ABE24E8962D00BF7289 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t9100837924E1A54B003E57AE /* Install clang-format hook */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/hooks/install.sh\",\n\t\t\t);\n\t\t\tname = \"Install clang-format hook\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if [ $CONFIGURATION == Debug ] ; then\\n\\t\\\"$SRCROOT/hooks/install.sh\\\"\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t9100833124DF1C82003E57AE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9100833D24DF1CCC003E57AE /* EmptyPlugIns.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t910C29CB24D910D300B9116B /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9100833024DF0F2C003E57AE /* AUBase.cpp in Sources */,\n\t\t\t\t914EC77D24D9D91A00725ABE /* AUBuffer.cpp in Sources */,\n\t\t\t\t9100835124DF3D54003E57AE /* AUEffectBase.cpp in Sources */,\n\t\t\t\t9100832E24DF0EB6003E57AE /* AUInputElement.cpp in Sources */,\n\t\t\t\t9100835424DF4125003E57AE /* AUMIDIBase.cpp in Sources */,\n\t\t\t\t9100835724DF9BAC003E57AE /* AUMIDIEffectBase.cpp in Sources */,\n\t\t\t\t9100832F24DF0EE7003E57AE /* AUOutputElement.cpp in Sources */,\n\t\t\t\t919B0CC62555C72000C59BDC /* AUBufferAllocator.cpp in Sources */,\n\t\t\t\t914EC77424D91FFA00725ABE /* AUPlugInDispatch.cpp in Sources */,\n\t\t\t\t914EC77E24D9DB3800725ABE /* AUScopeElement.cpp in Sources */,\n\t\t\t\t910C29D924D9115100B9116B /* ComponentBase.cpp in Sources */,\n\t\t\t\t9100835524DF421A003E57AE /* MusicDeviceBase.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t91E93ABC24E8962D00BF7289 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t64339772294B5DDC00DCD59F /* AUThreadSafeListTests.mm in Sources */,\n\t\t\t\t91E93AC324E8962D00BF7289 /* Tests.mm in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t9100833F24DF1DEF003E57AE /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 910C29CD24D910D300B9116B /* AudioUnitSDK */;\n\t\t\ttargetProxy = 9100833E24DF1DEF003E57AE /* PBXContainerItemProxy */;\n\t\t};\n\t\t91E93AC724E8962D00BF7289 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 910C29CD24D910D300B9116B /* AudioUnitSDK */;\n\t\t\ttargetProxy = 91E93AC624E8962D00BF7289 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t9100833924DF1C82003E57AE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tINFOPLIST_FILE = demos/EmptyPlugIns/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Bundles\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.apple.audio.EmptyPlugIns;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t\tWRAPPER_EXTENSION = bundle;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t9100833A24DF1C82003E57AE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tINFOPLIST_FILE = demos/EmptyPlugIns/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Bundles\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.apple.audio.EmptyPlugIns;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t\tWRAPPER_EXTENSION = bundle;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t910C29D024D910D300B9116B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++23\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_FLOAT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_PEDANTIC = YES;\n\t\t\t\tGCC_WARN_SIGN_COMPARE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 14.0;\n\t\t\t\tLLVM_LTO = NO;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"-Wall\",\n\t\t\t\t\t\"-Wextra\",\n\t\t\t\t\t\"-Wimport-preprocessor-directive-pedantic\",\n\t\t\t\t\t\"-Wunreachable-code-break\",\n\t\t\t\t\t\"-Wunreachable-code-return\",\n\t\t\t\t\t\"-Wvla\",\n\t\t\t\t\t\"-Wno-gnu-statement-expression-from-macro-expansion\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t910C29D124D910D300B9116B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++23\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_FLOAT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_USER_SCRIPT_SANDBOXING = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_PEDANTIC = YES;\n\t\t\t\tGCC_WARN_SIGN_COMPARE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 14.0;\n\t\t\t\tLLVM_LTO = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"-Wall\",\n\t\t\t\t\t\"-Wextra\",\n\t\t\t\t\t\"-Wimport-preprocessor-directive-pedantic\",\n\t\t\t\t\t\"-Wunreachable-code-break\",\n\t\t\t\t\t\"-Wunreachable-code-return\",\n\t\t\t\t\t\"-Wvla\",\n\t\t\t\t\t\"-Wno-gnu-statement-expression-from-macro-expansion\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t910C29D324D910D300B9116B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tOTHER_CFLAGS = \"-fvisibility=hidden\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/AudioUnitSDK;\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t910C29D424D910D300B9116B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tOTHER_CFLAGS = \"-fvisibility=hidden\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/AudioUnitSDK;\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t91E93AC824E8962D00BF7289 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tINFOPLIST_FILE = tests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.apple.audio.Tests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-Wno-gnu-statement-expression\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t91E93AC924E8962D00BF7289 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = include;\n\t\t\t\tINFOPLIST_FILE = tests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.apple.audio.Tests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-Wno-gnu-statement-expression\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t9100833824DF1C82003E57AE /* Build configuration list for PBXNativeTarget \"EmptyPlugIns\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t9100833924DF1C82003E57AE /* Debug */,\n\t\t\t\t9100833A24DF1C82003E57AE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t910C29C924D910D300B9116B /* Build configuration list for PBXProject \"AudioUnitSDK\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t910C29D024D910D300B9116B /* Debug */,\n\t\t\t\t910C29D124D910D300B9116B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t910C29D224D910D300B9116B /* Build configuration list for PBXNativeTarget \"AudioUnitSDK\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t910C29D324D910D300B9116B /* Debug */,\n\t\t\t\t910C29D424D910D300B9116B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t91E93ACA24E8962D00BF7289 /* Build configuration list for PBXNativeTarget \"Tests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t91E93AC824E8962D00BF7289 /* Debug */,\n\t\t\t\t91E93AC924E8962D00BF7289 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 910C29C624D910D300B9116B /* Project object */;\n}\n"
  },
  {
    "path": "AudioUnitSDK.xcodeproj/xcshareddata/xcschemes/AudioUnitSDK.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"910C29CD24D910D300B9116B\"\n               BuildableName = \"libAudioUnitSDK.a\"\n               BlueprintName = \"AudioUnitSDK\"\n               ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"910C29CD24D910D300B9116B\"\n            BuildableName = \"libAudioUnitSDK.a\"\n            BlueprintName = \"AudioUnitSDK\"\n            ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n   <InstallAction\n      buildConfiguration = \"Release\">\n   </InstallAction>\n</Scheme>\n"
  },
  {
    "path": "AudioUnitSDK.xcodeproj/xcshareddata/xcschemes/EmptyPlugIns.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"9100833424DF1C82003E57AE\"\n               BuildableName = \"EmptyPlugIns.bundle\"\n               BlueprintName = \"EmptyPlugIns\"\n               ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"9100833424DF1C82003E57AE\"\n            BuildableName = \"EmptyPlugIns.bundle\"\n            BlueprintName = \"EmptyPlugIns\"\n            ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n   <InstallAction\n      buildConfiguration = \"Release\">\n   </InstallAction>\n</Scheme>\n"
  },
  {
    "path": "AudioUnitSDK.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"91E93ABF24E8962D00BF7289\"\n               BuildableName = \"Tests.xctest\"\n               BlueprintName = \"Tests\"\n               ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"91E93ABF24E8962D00BF7289\"\n               BuildableName = \"Tests.xctest\"\n               BlueprintName = \"Tests\"\n               ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      enableAddressSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"91E93ABF24E8962D00BF7289\"\n            BuildableName = \"Tests.xctest\"\n            BlueprintName = \"Tests\"\n            ReferencedContainer = \"container:AudioUnitSDK.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n   <InstallAction\n      buildConfiguration = \"Release\">\n   </InstallAction>\n</Scheme>\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when\nan individual is representing the project or its community in public spaces.\nExamples of representing a project or community include using an official\nproject e-mail address, posting via an official social media account, or acting\nas an appointed representative at an online or offline event. Representation of\na project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the open source team at [opensource-conduct@group.apple.com](mailto:opensource-conduct@group.apple.com). All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4,\navailable at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html)"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guide\n\nThank you for your interest in contributing to the AudioUnit SDK! While this is an open-source project in spirit, it is intended to be updated infrequently with new version releases of the SDK. \nWhile you can open new pull requests WE ADVISE AGAINST IT and as such our response may be limited. Alternatively, you can open an issue which we will endeavour to address in the next official release.\n\n## Submitting a Pull Request\n\nBy submitting a pull request, you represent that you have the right to license your contribution to Apple and the community, and agree by submitting the patch that your contributions are licensed under the [LICENSE](LICENSE.md).\n\n*\"I agree that all information entered is original and owned by me, and I hereby provide an irrevocable, royalty-free license to Apple to use, modify, copy, publish, prepare derivate works of, distribute (including under the Apache License Version 2.0), such information and all intellectual property therein in whole or part, in perpetuity and worldwide, without any attribution.\"*\n\n\n## Code of Conduct\n\nWe ask that all community members read and observe our [Code of Conduct](CODE_OF_CONDUCT.md).\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "_clang-format",
    "content": "---\n# BasedOnStyle:  LLVM\nAccessModifierOffset: -4\nAlignAfterOpenBracket: DontAlign\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Right\nAlignOperands: true\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: true\nBinPackArguments: true\nBinPackParameters: true\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: WebKit\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nColumnLimit:     100\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: false\nDerivePointerBinding: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]\nIndentCaseLabels: false\nIndentWidth: 4\nKeepEmptyLinesAtTheStartOfBlocks: true\nMaxEmptyLinesToKeep: 2\nNamespaceIndentation: None\nObjCBlockIndentWidth: 4\nObjCSpaceAfterProperty: true\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Left\nQualifierAlignment: Left\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles: false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard: Cpp11\nStatementMacros: ['AUSDK_Catch']\nTabWidth: 4\nUseTab: ForContinuationAndIndentation\n...\n"
  },
  {
    "path": "_clang-tidy",
    "content": "---\nChecks:\n'\n*,\nclang-diagnostic-*,\nclang-analyzer-*,\n-clang-diagnostic-pragma-once-outside-header,\n-llvm-header-guard,\n-fuchsia-default-arguments-calls,\n-fuchsia-default-arguments-declarations,\n-fuchsia-multiple-inheritance,\n-fuchsia-overloaded-operator,\n-fuchsia-trailing-return,\n-hicpp-uppercase-literal-suffix,\n-google-default-arguments,\n-google-objc*,\n-google-readability-todo,\n-google-runtime-references,\n-modernize-use-trailing-return-type,\n-objc-property-declaration,\n-readability-implicit-bool-cast,\n-readability-uppercase-literal-suffix\n'\nWarningsAsErrors: ''\nHeaderFilterRegex: ''\nFormatStyle:     file\nCheckOptions:    \n  - key:             cppcoreguidelines-pro-type-member-init.IgnoreArrays\n    value:           '1'\n  - key: \t\t\t misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic\n    value:           '1'\n...\n"
  },
  {
    "path": "demos/EmptyPlugIns/EmptyPlugIns.cpp",
    "content": "/*!\n    @file        EmptyPlugIns.cpp\n    @copyright    © 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUEffectBase.h>\n#include <AudioUnitSDK/MusicDeviceBase.h>\n\n// -------------------------------------------------------------------------------------------------\n\nclass AUBase_Derived : public ausdk::AUBase {\n\tusing Base = ausdk::AUBase;\n\npublic:\n\texplicit AUBase_Derived(AudioComponentInstance ci) : Base{ ci, 1, 1 } {}\n\n\tbool StreamFormatWritable(AudioUnitScope, AudioUnitElement) override { return true; }\n\n\tbool CanScheduleParameters() const noexcept AUSDK_RTSAFE override { return false; }\n};\n\nAUSDK_COMPONENT_ENTRY(ausdk::AUBaseFactory, AUBase_Derived)\n\n// -------------------------------------------------------------------------------------------------\n\nclass AUEffectBase_Derived : public ausdk::AUEffectBase {\n\tusing Base = ausdk::AUEffectBase;\n\npublic:\n\texplicit AUEffectBase_Derived(AudioComponentInstance ci) : Base{ ci, true } {}\n};\n\nAUSDK_COMPONENT_ENTRY(ausdk::AUBaseFactory, AUEffectBase_Derived)\n\n// -------------------------------------------------------------------------------------------------\n\nclass MusicDeviceBase_Derived : public ausdk::MusicDeviceBase {\n\tusing Base = ausdk::MusicDeviceBase;\n\npublic:\n\texplicit MusicDeviceBase_Derived(AudioComponentInstance ci) : Base{ ci, 0, 1 } {}\n\n\tbool StreamFormatWritable(AudioUnitScope, AudioUnitElement) override { return true; }\n\n\tbool CanScheduleParameters() const noexcept AUSDK_RTSAFE override { return false; }\n};\n\nAUSDK_COMPONENT_ENTRY(ausdk::AUMusicDeviceFactory, MusicDeviceBase_Derived)\n"
  },
  {
    "path": "demos/EmptyPlugIns/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "hooks/install.sh",
    "content": "#! /bin/sh\n\ngit rev-parse 2> /dev/null\nif [ $? != 0 ]; then\n\techo \"not currently working in a git repository, therefore aborting `basename $0`\"\n\texit 0\nfi\n\nset -e\n\nSOURCE_DIR=\"`git rev-parse --show-toplevel`/hooks\"\nINSTALL_DIR=$(git rev-parse --git-path hooks)\nFILENAME=\"pre-commit\"\n\nmkdir -p \"${INSTALL_DIR}\"\ncp -f \"${SOURCE_DIR}\"/${FILENAME} \"${INSTALL_DIR}\"/${FILENAME}\nchmod +x \"${INSTALL_DIR}\"/${FILENAME}\n"
  },
  {
    "path": "hooks/pre-commit",
    "content": "#! /bin/zsh\n# This pre-commit hook uses clang-format to format the staged changes.\n\nif ! git rev-parse --verify HEAD >/dev/null 2>&1\nthen\n\techo \"not currently working in a git repository or unable to verify HEAD, therefore skipping `basename $0`\"\n\texit 0\nfi\n\nset -e\n\nREPO_ROOT=$(git rev-parse --show-toplevel)\nDIFF_ARGS=\"--name-only --diff-filter=ACMRT\"\ngit diff-index ${=DIFF_ARGS} --cached HEAD | grep -E \"\\.(h|hpp|c|cpp|m|mm)$\" | while read -r FILE\ndo\n\tFILE_PATH=\"${REPO_ROOT}\"/\"${FILE}\"\n\tif [[ `git diff ${=DIFF_ARGS} \"${FILE_PATH}\"` == $FILE ]]\n\tthen\n\t\techo -e \"\\xF0\\x9F\\x94\\xA5 \\xE2\\x98\\xA0 \\xF0\\x9F\\x94\\xA5 WARNING: creating a stash for file due to unstaged changes: ${FILE}\"\n\t\t# format before stashing to avoid a merge conflict when applying the stash after commit\n\t\txcrun clang-format -i \"${FILE_PATH}\"\n\t\tgit stash push -k -q -m \"pre-clang-format: ${FILE}\" -- \"${FILE_PATH}\"\n    fi\n\n\txcrun clang-format -i \"${FILE_PATH}\"\n\tgit add \"${FILE_PATH}\"\ndone\n"
  },
  {
    "path": "include/AudioUnitSDK/AUBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n\n#ifndef AudioUnitSDK_AUBase_h\n#define AudioUnitSDK_AUBase_h\n\n// module\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUInputElement.h>\n#include <AudioUnitSDK/AUOutputElement.h>\n#include <AudioUnitSDK/AUPlugInDispatch.h>\n#include <AudioUnitSDK/AUScopeElement.h>\n#include <AudioUnitSDK/AUThreadSafeList.h>\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/ComponentBase.h>\n\n// OS\n#include <AudioToolbox/AudioComponent.h>\n#include <AudioToolbox/AudioUnitProperties.h>\n\n#if AUSDK_HAVE_MUSIC_DEVICE\n#include <AudioToolbox/MusicDevice.h>\n#endif\n\n#if AUSDK_HAVE_MIDI2\n#include <CoreMIDI/MIDIServices.h>\n#endif\n\n// std\n#include <algorithm>\n#include <array>\n#include <memory>\n#include <mutex>\n#include <thread>\n#include <vector>\n\n// ________________________________________________________________________\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/*!\n\t@class\tAUBase\n\t@brief\tAbstract base class for an Audio Unit implementation.\n*/\nclass AUBase : public ComponentBase {\npublic:\n\tconstexpr static double kAUDefaultSampleRate = 44100.0;\n#if !TARGET_OS_WIN32\n\tconstexpr static UInt32 kAUDefaultMaxFramesPerSlice = 1156;\n\t// this allows enough default frames for a 512 dest 44K and SRC from 96K\n\t// add a padding of 4 frames for any vector rounding\n#else\n\tconstexpr static UInt32 kAUDefaultMaxFramesPerSlice = 2048;\n#endif\n\n\tAUBase(AudioComponentInstance inInstance, UInt32 numInputElements, UInt32 numOutputElements,\n\t\tUInt32 numGroupElements = 0);\n\t~AUBase() override;\n\n\tAUBase(const AUBase&) = delete;\n\tAUBase(AUBase&&) = delete;\n\tAUBase& operator=(const AUBase&) = delete;\n\tAUBase& operator=(AUBase&&) = delete;\n\n\t/// Called immediately after construction, when virtual methods work. Or, a subclass may call\n\t/// this in order to have access to elements in its constructor.\n\tvoid CreateElements();\n\n\tvirtual void CreateExtendedElements() {}\n\n#pragma mark -\n#pragma mark AU dispatch\n\t// ________________________________________________________________________\n\t// Virtual methods (mostly) directly corresponding to the entry points.  Many of these\n\t// have useful implementations here and will not need overriding.\n\n\t/// Implements the entry point and ensures that Initialize is called exactly once from an\n\t/// uninitialized state.\n\tOSStatus DoInitialize();\n\n\t// Overrides to this method can assume that they will only be called exactly once\n\t// when transitioning from an uninitialized state.\n\tvirtual OSStatus Initialize();\n\n\t[[nodiscard]] bool IsInitialized() const noexcept { return mInitialized; }\n\t[[nodiscard]] bool HasBegunInitializing() const noexcept { return mHasBegunInitializing; }\n\n\t/// Implements the entry point and ensures that Cleanup is called exactly once from an\n\t/// initialized state.\n\tvoid DoCleanup();\n\n\t// Overrides to this method can assume that they will only be called exactly once\n\t// when transitioning from an initialized state to an uninitialized state.\n\tvirtual void Cleanup();\n\n\t/// Implements the entry point and ensures that critical audio Reset work always occurs\n\tOSStatus DoReset(AudioUnitScope inScope, AudioUnitElement inElement);\n\n\t/// Not realtime-safe by contract, but if a derived class wishes to implement a safe Reset,\n\t/// it can call BaseReset().\n\tvirtual OSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement);\n\n\tOSStatus BaseReset(AudioUnitScope /*inScope*/, AudioUnitElement /*inElement*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\n\t// Note about GetPropertyInfo, GetProperty, SetProperty:\n\t// Certain properties are trapped out in these dispatch functions and handled with different\n\t// virtual methods.  (To discourage hacks and keep vtable size down, these are non-virtual)\n\n\tOSStatus DispatchGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable);\n\tOSStatus DispatchGetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData);\n\tOSStatus DispatchSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize);\n\tOSStatus DispatchRemovePropertyValue(\n\t\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement);\n\n\tvirtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable);\n\tvirtual OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData);\n\tvirtual OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize);\n\tvirtual OSStatus RemovePropertyValue(\n\t\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement);\n\n\tvirtual OSStatus AddPropertyListener(\n\t\tAudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcRefCon);\n\tvirtual OSStatus RemovePropertyListener(AudioUnitPropertyID inID,\n\t\tAudioUnitPropertyListenerProc inProc, void* inProcRefCon, bool refConSpecified);\n\n\tvirtual OSStatus SetRenderNotification(AURenderCallback inProc, void* inRefCon);\n\tvirtual OSStatus RemoveRenderNotification(AURenderCallback inProc, void* inRefCon);\n\n\tvirtual OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, AudioUnitParameterValue& outValue) AUSDK_RTSAFE;\n\n\tvirtual OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, AudioUnitParameterValue inValue,\n\t\tUInt32 inBufferOffsetInFrames) AUSDK_RTSAFE;\n\n\t// N.B. For internal use; asserts that the ParameterID is valid.\n\tAudioUnitParameterValue GetParameterRT(AudioUnitParameterID paramID) AUSDK_RTSAFE\n\t{\n\t\treturn Globals()->GetParameterRT(paramID);\n\t}\n\tvoid SetParameterRT(AudioUnitParameterID paramID, AudioUnitParameterValue inValue) AUSDK_RTSAFE\n\t{\n\t\tGlobals()->SetParameterRT(paramID, inValue);\n\t}\n\n\t[[nodiscard]] virtual bool CanScheduleParameters() const AUSDK_RTSAFE = 0;\n\n\tvirtual OSStatus ScheduleParameter(\n\t\tconst AudioUnitParameterEvent* inParameterEvent, UInt32 inNumEvents) AUSDK_RTSAFE;\n\n\t// The non-virtual DoRender/etc. methods are noexcept because they catch any exceptions.\n\n\tOSStatus DoRender(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,\n\t\tUInt32 inBusNumber, UInt32 inFramesToProcess,\n\t\tAudioBufferList& ioData) noexcept AUSDK_RTSAFE;\n\n\tOSStatus DoProcess(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,\n\t\tUInt32 inFramesToProcess, AudioBufferList& ioData) noexcept AUSDK_RTSAFE;\n\n\tOSStatus DoProcessMultiple(AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioTimeStamp& inTimeStamp, UInt32 inFramesToProcess,\n\t\tUInt32 inNumberInputBufferLists, const AudioBufferList** inInputBufferLists,\n\t\tUInt32 inNumberOutputBufferLists,\n\t\tAudioBufferList** ioOutputBufferLists) noexcept AUSDK_RTSAFE;\n\n\tvirtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& /*ioActionFlags*/,\n\t\tconst AudioBufferList& /*inBuffer*/, AudioBufferList& /*outBuffer*/,\n\t\tUInt32 /*inFramesToProcess*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\tvirtual OSStatus ProcessMultipleBufferLists(AudioUnitRenderActionFlags& /*ioActionFlags*/,\n\t\tUInt32 /*inFramesToProcess*/, UInt32 /*inNumberInputBufferLists*/,\n\t\tconst AudioBufferList** /*inInputBufferLists*/, UInt32 /*inNumberOutputBufferLists*/,\n\t\tAudioBufferList** /*ioOutputBufferLists*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\tvirtual OSStatus ComplexRender(AudioUnitRenderActionFlags& /*ioActionFlags*/,\n\t\tconst AudioTimeStamp& /*inTimeStamp*/, UInt32 /*inOutputBusNumber*/,\n\t\tUInt32 /*inNumberOfPackets*/, UInt32* /*outNumberOfPackets*/,\n\t\tAudioStreamPacketDescription* /*outPacketDescriptions*/, AudioBufferList& /*ioData*/,\n\t\tvoid* /*outMetadata*/, UInt32* /*outMetadataByteSize*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\t// Override this method if your AU processes multiple output busses completely independently --\n\t// you'll want to just call Render without the NeedsToRender check.\n\t// Otherwise, override Render().\n\t//\n\t// N.B. Implementations of this method can assume that the output's buffer list has already been\n\t// prepared and access it with GetOutput(inBusNumber)->GetBufferList() instead of\n\t// GetOutput(inBusNumber)->PrepareBuffer(nFrames) -- if PrepareBuffer is called, a\n\t// copy may occur after rendering.\n\tvirtual OSStatus RenderBus(AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioTimeStamp& inTimeStamp, UInt32 /*inBusNumber*/,\n\t\tUInt32 inNumberFrames) AUSDK_RTSAFE\n\t{\n\t\tif (NeedsToRender(inTimeStamp)) {\n\t\t\treturn Render(ioActionFlags, inTimeStamp, inNumberFrames);\n\t\t}\n\t\treturn noErr; // was presumably already rendered via another bus\n\t}\n\n\t// N.B. For a unit with only one output bus, it can assume in its implementation of this\n\t// method that the output's buffer list has already been prepared and access it with\n\t// GetOutput(0)->GetBufferList() instead of GetOutput(0)->PrepareBuffer(nFrames)\n\t//  -- if PrepareBuffer is called, a copy may occur after rendering.\n\tvirtual OSStatus Render(AudioUnitRenderActionFlags& /*ioActionFlags*/,\n\t\tconst AudioTimeStamp& /*inTimeStamp*/, UInt32 /*inNumberFrames*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\n\n#pragma mark -\n#pragma mark Property Dispatch\n\n\t// ________________________________________________________________________\n\t// These are called from DispatchGetProperty/DispatchGetPropertyInfo/DispatchSetProperty\n\n\tvirtual bool BusCountWritable(AudioUnitScope /*inScope*/) { return false; }\n\tvirtual OSStatus SetBusCount(AudioUnitScope inScope, UInt32 inCount);\n\tvirtual OSStatus SetConnection(const AudioUnitConnection& inConnection);\n\tvirtual OSStatus SetInputCallback(\n\t\tUInt32 inPropertyID, AudioUnitElement inElement, AURenderCallback inProc, void* inRefCon);\n\n\tvirtual OSStatus GetParameterList(\n\t\tAudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters);\n\t// outParameterList may be a null pointer\n\tvirtual OSStatus GetParameterInfo(AudioUnitScope inScope, AudioUnitParameterID inParameterID,\n\t\tAudioUnitParameterInfo& outParameterInfo);\n\n\tvirtual OSStatus GetParameterHistoryInfo(AudioUnitScope inScope,\n\t\tAudioUnitParameterID inParameterID, Float32& outUpdatesPerSecond,\n\t\tFloat32& outHistoryDurationInSeconds);\n\tvirtual OSStatus SaveState(CFPropertyListRef* outData);\n\tvirtual void SaveExtendedScopes(CFMutableDataRef /*outData*/) {}\n\tvirtual OSStatus RestoreState(CFPropertyListRef plist);\n\tvirtual OSStatus GetParameterValueStrings(\n\t\tAudioUnitScope inScope, AudioUnitParameterID inParameterID, CFArrayRef* outStrings);\n\tvirtual OSStatus CopyClumpName(AudioUnitScope inScope, UInt32 inClumpID,\n\t\tUInt32 inDesiredNameLength, CFStringRef* outClumpName);\n\tvirtual OSStatus GetPresets(CFArrayRef* outData) const;\n\n\t/// Set the default preset for the unit. The number of the preset must be >= 0 and the name\n\t/// should be valid, or the preset will be rejected.\n\tbool SetAFactoryPresetAsCurrent(const AUPreset& inPreset);\n\n\t// Called when the host sets a new, valid preset.\n\t// If this is a valid preset, then the subclass sets its state to that preset\n\t// and returns noErr.\n\t// If not a valid preset, return an error, and the pre-existing preset is restored.\n\tvirtual OSStatus NewFactoryPresetSet(const AUPreset& inNewFactoryPreset);\n\tvirtual OSStatus NewCustomPresetSet(const AUPreset& inNewCustomPreset);\n#if AUSDK_HAVE_UI\n\tvirtual CFURLRef CopyIconLocation();\n#endif\n\n\t// default is no latency, and unimplemented tail time\n\tvirtual Float64 GetLatency() AUSDK_RTSAFE { return 0.0; }\n\tvirtual Float64 GetTailTime() AUSDK_RTSAFE { return 0.0; }\n\tvirtual bool SupportsTail() AUSDK_RTSAFE { return false; }\n\n\t// Stream formats: scope will always be input or output\n\tbool IsStreamFormatWritable(AudioUnitScope scope, AudioUnitElement element);\n\n\tvirtual bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) = 0;\n\n\t// pass in a pointer to get the struct, and num channel infos\n\t// you can pass in NULL to just get the number\n\t// a return value of 0 (the default in AUBase) means the property is not supported...\n\tvirtual UInt32 SupportedNumChannels(const AUChannelInfo** outInfo);\n\n\t/// Will only be called after StreamFormatWritable has succeeded. Default implementation\n\t/// requires non-interleaved native-endian 32-bit float, any sample rate, any number of\n\t/// channels; override when other formats are supported.  A subclass's override can choose to\n\t/// always return true and trap invalid formats in ChangeStreamFormat.\n\tvirtual bool ValidFormat(AudioUnitScope inScope, AudioUnitElement inElement,\n\t\tconst AudioStreamBasicDescription& inNewFormat);\n\n\tvirtual AudioStreamBasicDescription GetStreamFormat(\n\t\tAudioUnitScope inScope, AudioUnitElement inElement) AUSDK_RTSAFE_LOOSE;\n\n\t// Will only be called after StreamFormatWritable\n\t// and ValidFormat have succeeded.\n\tvirtual OSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,\n\t\tconst AudioStreamBasicDescription& inPrevFormat,\n\t\tconst AudioStreamBasicDescription& inNewFormat);\n\n\t// ________________________________________________________________________\n\t// Methods useful for subclasses\n\tAUScope& GetScope(AudioUnitScope inScope)\n\t{\n\t\tif (inScope >= kNumScopes) {\n\t\t\tAUScope* const scope = GetScopeExtended(inScope);\n\n\t\t\tThrowQuietIf(scope == nullptr, kAudioUnitErr_InvalidScope);\n\t\t\treturn *scope;\n\t\t}\n\t\treturn mScopes[inScope]; // NOLINT\n\t}\n\n\tvirtual AUScope* GetScopeExtended(AudioUnitScope /*inScope*/) AUSDK_RTSAFE { return nullptr; }\n\n\tAUScope& GlobalScope() { return mScopes[kAudioUnitScope_Global]; }\n\tAUScope& Inputs() { return mScopes[kAudioUnitScope_Input]; }\n\tAUScope& Outputs() { return mScopes[kAudioUnitScope_Output]; }\n\tAUScope& Groups() { return mScopes[kAudioUnitScope_Group]; }\n\n\tAUElement* Globals() AUSDK_RTSAFE\n\t{\n\t\tauto maybeElem = mScopes[kAudioUnitScope_Global].GetElementOrError(0);\n\t\tAUSDK_Assert(maybeElem);\n\t\treturn maybeElem.get();\n\t}\n\n\tvoid SetNumberOfElements(AudioUnitScope inScope, UInt32 numElements);\n\tvirtual std::unique_ptr<AUElement> CreateElement(\n\t\tAudioUnitScope scope, AudioUnitElement element);\n\n\n\tAUElement* GetElement(AudioUnitScope inScope, AudioUnitElement inElement)\n\t{\n\t\treturn GetScope(inScope).GetElement(inElement);\n\t}\n\n\tAUSDK_DEPRECATED(\"Use IOElement()\")\n\tAUIOElement* GetIOElement(AudioUnitScope inScope, AudioUnitElement inElement)\n\t{\n\t\treturn &IOElement(inScope, inElement);\n\t}\n\n\tAUIOElement& IOElement(AudioUnitScope inScope, AudioUnitElement inElement)\n\t{\n\t\treturn *GetScope(inScope).GetIOElement(inElement);\n\t}\n\n\tAUSDK_DEPRECATED(\"Use Element()\")\n\tAUElement* SafeGetElement(AudioUnitScope inScope, AudioUnitElement inElement)\n\t{\n\t\treturn &Element(inScope, inElement);\n\t}\n\n\tAUElement& Element(AudioUnitScope inScope, AudioUnitElement inElement)\n\t{\n\t\treturn *GetScope(inScope).SafeGetElement(inElement);\n\t}\n\n\tAUSDK_DEPRECATED(\"Use Input()\")\n\tAUInputElement* GetInput(AudioUnitElement inElement) { return &Input(inElement); }\n\tAUInputElement& Input(AudioUnitElement inElement)\n\t{\n\t\treturn static_cast<AUInputElement&>(*Inputs().SafeGetElement(inElement)); // NOLINT downcast\n\t}\n\n\tAUSDK_DEPRECATED(\"Use Output()\")\n\tAUOutputElement* GetOutput(AudioUnitElement inElement) { return &Output(inElement); }\n\tAUOutputElement& Output(AudioUnitElement inElement)\n\t{\n\t\treturn static_cast<AUOutputElement&>( // NOLINT downcast\n\t\t\t*Outputs().SafeGetElement(inElement));\n\t}\n\n\tAUSDK_DEPRECATED(\"Use Group()\")\n\tAUElement* GetGroup(AudioUnitElement inElement) { return &Group(inElement); }\n\tAUElement& Group(AudioUnitElement inElement) { return *Groups().SafeGetElement(inElement); }\n\n\tExpectedPtr<AUScope> GetScopeOrError(AudioUnitScope inScope) AUSDK_RTSAFE\n\t{\n\t\tif (inScope >= kNumScopes) {\n\t\t\tif (auto* scope = GetScopeExtended(inScope)) {\n\t\t\t\treturn *scope;\n\t\t\t}\n\t\t\treturn Unexpected(kAudioUnitErr_InvalidScope);\n\t\t}\n\t\treturn mScopes[inScope]; // NOLINT\n\t}\n\n\tExpectedPtr<AUIOElement> GetIOElementOrError(\n\t\tAudioUnitScope inScope, AudioUnitElement inElement) AUSDK_RTSAFE\n\t{\n\t\tAUScope& scope = AUSDK_UnwrapOrReturnUnexpected(GetScopeOrError(inScope));\n\t\treturn scope.GetIOElementOrError(inElement);\n\t}\n\n\tExpectedPtr<AUElement> GetElementOrError(\n\t\tAudioUnitScope inScope, AudioUnitElement inElement) AUSDK_RTSAFE\n\t{\n\t\tAUScope& scope = AUSDK_UnwrapOrReturnUnexpected(GetScopeOrError(inScope));\n\t\treturn scope.GetElementOrError(inElement);\n\t}\n\n\ttemplate <typename E = AUInputElement>\n\tExpectedPtr<E> GetInputOrError(AudioUnitElement inElement) AUSDK_RTSAFE\n\t{\n\t\treturn Inputs().GetElementOrError<E>(inElement);\n\t}\n\n\ttemplate <typename E = AUOutputElement>\n\tExpectedPtr<E> GetOutputOrError(AudioUnitElement inElement) AUSDK_RTSAFE\n\t{\n\t\treturn Outputs().GetElementOrError<E>(inElement);\n\t}\n\n\t// Since almost every AudioUnit has at least one output element, this method is useful for\n\t// obtaining output 0 without requiring error checking/handling.\n\ttemplate <typename E = AUOutputElement>\n\tE& GetOutput0() AUSDK_RTSAFE\n\t{\n\t\tauto maybeElem = Outputs().GetElementOrError<E>(0);\n\t\tAUSDK_Assert(maybeElem);\n\t\treturn *maybeElem;\n\t}\n\n\t// Most AudioUnits have at least one input element, so this method is useful for\n\t// obtaining input 0 without requiring error checking/handling.\n\ttemplate <typename E = AUInputElement>\n\tE& GetInput0() AUSDK_RTSAFE\n\t{\n\t\tauto maybeElem = Inputs().GetElementOrError<E>(0);\n\t\tAUSDK_Assert(maybeElem);\n\t\treturn *maybeElem;\n\t}\n\n\tExpectedPtr<AUElement> GetGroupOrError(AudioUnitElement inElement) AUSDK_RTSAFE\n\t{\n\t\treturn Groups().GetElementOrError(inElement);\n\t}\n\n\tOSStatus PullInput(UInt32 inBusNumber, AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioTimeStamp& inTimeStamp, UInt32 inNumberFrames) AUSDK_RTSAFE\n\t{\n\t\tAUInputElement& input = AUSDK_UnwrapOrReturnError(GetInputOrError(inBusNumber));\n\t\treturn input.PullInput(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames);\n\t}\n\n\t[[nodiscard]] UInt32 GetMaxFramesPerSlice() const noexcept { return mMaxFramesPerSlice; }\n\n\t[[nodiscard]] bool UsesFixedBlockSize() const noexcept { return mUsesFixedBlockSize; }\n\n\tvoid SetUsesFixedBlockSize(bool inUsesFixedBlockSize) noexcept\n\t{\n\t\tmUsesFixedBlockSize = inUsesFixedBlockSize;\n\t}\n\n\t[[nodiscard]] virtual bool InRenderThread() const AUSDK_RTSAFE\n\t{\n\t\t// Marked unsafe because the library function isn't annotated.\n\t\treturn AUSDK_RT_UNSAFE(std::this_thread::get_id()) == mRenderThreadID;\n\t}\n\n\t/// Says whether an input is connected or has a callback.\n\t/// Not realtime-safe; use bus->IsActive().\n\tbool HasInput(AudioUnitElement inElement)\n\t{\n\t\tauto* const in =\n\t\t\tstatic_cast<AUInputElement*>(Inputs().GetElement(inElement)); // NOLINT downcast\n\t\treturn in != nullptr && in->IsActive();\n\t}\n\n\tvirtual void PropertyChanged(\n\t\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement);\n\n\t// These calls can be used to call a Host's Callbacks. The method returns -1 if the host\n\t// hasn't supplied the callback. Any other result is returned by the host.\n\t// As in the API contract, for a parameter's value, you specify a pointer\n\t// to that data type. Specify NULL for a parameter that you are not interested\n\t// as this can save work in the host.\n\tOSStatus CallHostBeatAndTempo(Float64* outCurrentBeat, Float64* outCurrentTempo) const\n\t{\n\t\treturn (mHostCallbackInfo.beatAndTempoProc != nullptr\n\t\t\t\t\t? (*mHostCallbackInfo.beatAndTempoProc)(\n\t\t\t\t\t\t  mHostCallbackInfo.hostUserData, outCurrentBeat, outCurrentTempo)\n\t\t\t\t\t: -1);\n\t}\n\n\tOSStatus CallHostMusicalTimeLocation(UInt32* outDeltaSampleOffsetToNextBeat,\n\t\tFloat32* outTimeSig_Numerator, UInt32* outTimeSig_Denominator,\n\t\tFloat64* outCurrentMeasureDownBeat) const\n\t{\n\t\treturn (mHostCallbackInfo.musicalTimeLocationProc != nullptr\n\t\t\t\t\t? (*mHostCallbackInfo.musicalTimeLocationProc)(mHostCallbackInfo.hostUserData,\n\t\t\t\t\t\t  outDeltaSampleOffsetToNextBeat, outTimeSig_Numerator,\n\t\t\t\t\t\t  outTimeSig_Denominator, outCurrentMeasureDownBeat)\n\t\t\t\t\t: -1);\n\t}\n\n\tOSStatus CallHostTransportState(Boolean* outIsPlaying, Boolean* outTransportStateChanged,\n\t\tFloat64* outCurrentSampleInTimeLine, Boolean* outIsCycling, Float64* outCycleStartBeat,\n\t\tFloat64* outCycleEndBeat) const\n\t{\n\t\treturn (mHostCallbackInfo.transportStateProc != nullptr\n\t\t\t\t\t? (*mHostCallbackInfo.transportStateProc)(mHostCallbackInfo.hostUserData,\n\t\t\t\t\t\t  outIsPlaying, outTransportStateChanged, outCurrentSampleInTimeLine,\n\t\t\t\t\t\t  outIsCycling, outCycleStartBeat, outCycleEndBeat)\n\t\t\t\t\t: -1);\n\t}\n\n\t[[nodiscard]] const char* GetLoggingString() const noexcept;\n\n\tAUMutex* GetMutex() noexcept { return mAUMutex; }\n\t// The caller of SetMutex is responsible for the managing the lifetime of the\n\t// mutex object and, if deleted before the AUBase instance, is responsible\n\t// for calling SetMutex(nullptr)\n\tvoid SetMutex(AUMutex* mutex) noexcept { mAUMutex = mutex; }\n\n#pragma mark -\n#pragma mark AU Output Base Dispatch\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\t// output unit methods\n\tvirtual OSStatus Start() { return kAudio_UnimplementedError; }\n\n\tvirtual OSStatus Stop() { return kAudio_UnimplementedError; }\n\n#pragma mark -\n#pragma mark AU Music Base Dispatch\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\t// music device/music effect methods\n\n\tvirtual OSStatus MIDIEvent(UInt32 /*inStatus*/, UInt32 /*inData1*/, UInt32 /*inData2*/,\n\t\tUInt32 /*inOffsetSampleFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\tvirtual OSStatus SysEx(const UInt8* /*inData*/, UInt32 /*inLength*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n#if AUSDK_HAVE_MIDI2\n\tvirtual OSStatus MIDIEventList(\n\t\tUInt32 /*inOffsetSampleFrame*/, const MIDIEventList* /*eventList*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n#endif\n\n#if AUSDK_HAVE_MUSIC_DEVICE\n\tvirtual OSStatus StartNote(MusicDeviceInstrumentID /*inInstrument*/,\n\t\tMusicDeviceGroupID /*inGroupID*/, NoteInstanceID* /*outNoteInstanceID*/,\n\t\tUInt32 /*inOffsetSampleFrame*/, const MusicDeviceNoteParams& /*inParams*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\tvirtual OSStatus StopNote(MusicDeviceGroupID /*inGroupID*/, NoteInstanceID /*inNoteInstanceID*/,\n\t\tUInt32 /*inOffsetSampleFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\t/// Obsolete\n\tstatic OSStatus PrepareInstrument(MusicDeviceInstrumentID /*inInstrument*/)\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n\n\t/// Obsolete\n\tstatic OSStatus ReleaseInstrument(MusicDeviceInstrumentID /*inInstrument*/)\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\t// ________________________________________________________________________\n\nprotected:\n#pragma mark -\n#pragma mark Implementation methods\n\tvoid PostConstructorInternal() final;\n\tvoid PreDestructorInternal() final;\n\n\t/// needs to be called when mMaxFramesPerSlice changes\n\tvirtual void ReallocateBuffers();\n\n\tvirtual void DeallocateIOBuffers();\n\n\tstatic void FillInParameterName(\n\t\tAudioUnitParameterInfo& ioInfo, CFStringRef inName, bool inShouldRelease)\n\t{\n\t\tioInfo.cfNameString = inName;\n\t\tioInfo.flags |= kAudioUnitParameterFlag_HasCFNameString;\n\t\tif (inShouldRelease) {\n\t\t\tioInfo.flags |= kAudioUnitParameterFlag_CFNameRelease;\n\t\t}\n\t\tCFStringGetCString(\n\t\t\tinName, std::data(ioInfo.name), std::ssize(ioInfo.name), kCFStringEncodingUTF8);\n\t}\n\n\tstatic void HasClump(AudioUnitParameterInfo& ioInfo, UInt32 inClumpID) noexcept\n\t{\n\t\tioInfo.clumpID = inClumpID;\n\t\tioInfo.flags |= kAudioUnitParameterFlag_HasClump;\n\t}\n\n\tvirtual void SetMaxFramesPerSlice(UInt32 nFrames);\n\n\t[[nodiscard]] virtual OSStatus CanSetMaxFrames() const;\n\n\t[[nodiscard]] bool WantsRenderThreadID() const noexcept { return mWantsRenderThreadID; }\n\n\tvoid SetWantsRenderThreadID(bool inFlag);\n\n\tOSStatus SetRenderError(OSStatus inErr) AUSDK_RTSAFE\n\t{\n\t\tif (inErr != noErr && mLastRenderError == 0) {\n\t\t\tmLastRenderError = inErr;\n\t\t\tAUSDK_RT_UNSAFE_BEGIN(\"FIXME: PropertyChanged is unsafe\")\n\t\t\tPropertyChanged(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0);\n\t\t\tAUSDK_RT_UNSAFE_END\n\t\t}\n\t\treturn inErr;\n\t}\n\n\tstruct PropertyListener {\n\t\tAudioUnitPropertyID propertyID{ 0 };\n\t\tAudioUnitPropertyListenerProc listenerProc{ nullptr };\n\t\tvoid* listenerRefCon{ nullptr };\n\t};\n\tusing PropertyListeners = std::vector<PropertyListener>;\n\n\t[[nodiscard]] const PropertyListeners& GetPropertyListeners() const noexcept\n\t{\n\t\treturn mPropertyListeners;\n\t}\n\n\tHostCallbackInfo& GetHostCallbackInfo() noexcept { return mHostCallbackInfo; }\n\nprivate:\n\t// shared between Render and RenderSlice, inlined to minimize function call overhead\n\tOSStatus DoRenderBus(AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioTimeStamp& inTimeStamp, UInt32 inBusNumber, AUOutputElement& theOutput,\n\t\tUInt32 inNumberFrames, AudioBufferList& ioData) AUSDK_RTSAFE\n\t{\n\t\tExpectedPtr<AudioBufferList> maybeBuf;\n\t\tif (ioData.mBuffers[0].mData == nullptr ||\n\t\t\t(theOutput.WillAllocateBuffer() && Outputs().GetNumberOfElements() > 1)) {\n\t\t\t// will render into cache buffer\n\t\t\tmaybeBuf = theOutput.PrepareBufferOrError(inNumberFrames);\n\t\t} else {\n\t\t\t// will render into caller's buffer\n\t\t\tmaybeBuf = theOutput.SetBufferListOrError(ioData);\n\t\t}\n\t\tif (!maybeBuf) {\n\t\t\treturn maybeBuf.error();\n\t\t}\n\n\t\tAUSDK_Require_noerr(RenderBus(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames));\n\t\tExpected<void> copyResult;\n\t\tif (ioData.mBuffers[0].mData == nullptr) {\n\t\t\tcopyResult = theOutput.CopyBufferListToOrError(ioData);\n\t\t} else {\n\t\t\tcopyResult = theOutput.CopyBufferContentsToOrError(ioData);\n\t\t\ttheOutput.InvalidateBufferList();\n\t\t}\n\t\tif (!copyResult) {\n\t\t\treturn copyResult.error();\n\t\t}\n\t\treturn noErr;\n\t}\n\n\tbool HasIcon();\n\n\t[[nodiscard]] std::string CreateLoggingString() const;\n\nprotected:\n\t//. Returns size. outLayoutPtr may be null if querying only for size.\n\tvirtual UInt32 GetAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element,\n\t\tAudioChannelLayout* outLayoutPtr, bool& outWritable);\n\n\t/// Layout is non-null.\n\tvirtual OSStatus SetAudioChannelLayout(\n\t\tAudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout);\n\n\tvirtual OSStatus RemoveAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element);\n\n\tvirtual std::vector<AudioChannelLayoutTag> GetChannelLayoutTags(\n\t\tAudioUnitScope scope, AudioUnitElement element);\n\n\tbool NeedsToRender(const AudioTimeStamp& inTimeStamp)\n\t{\n\t\tconst bool needsToRender = (inTimeStamp.mSampleTime != mCurrentRenderTime.mSampleTime);\n\t\tif (needsToRender) { // only copy this if we need to render\n\t\t\tmCurrentRenderTime = inTimeStamp;\n\t\t}\n\t\treturn needsToRender;\n\t}\n\n\t// Scheduled parameter implementation:\n\n\tusing ParameterEventList = std::vector<AudioUnitParameterEvent>;\n\n\t// Usually, you won't override this method.  You only need to call this if your DSP code\n\t// is prepared to handle scheduled immediate and ramped parameter changes.\n\t// Before calling this method, it is assumed you have already called PullInput() on the input\n\t// busses for which the DSP code depends.  ProcessForScheduledParams() will call (potentially\n\t// repeatedly) virtual method ProcessScheduledSlice() to perform the actual DSP for a given\n\t// sub-division of the buffer.  The job of ProcessForScheduledParams() is to sub-divide the\n\t// buffer into smaller pieces according to the scheduled times found in the ParameterEventList\n\t// (usually coming directly from a previous call to ScheduleParameter() ), setting the\n\t// appropriate immediate or ramped parameter values for the corresponding scopes and elements,\n\t// then calling ProcessScheduledSlice() to do the actual DSP for each of these divisions.\n\tvirtual OSStatus ProcessForScheduledParams(\n\t\tParameterEventList& inParamList, UInt32 inFramesToProcess, void* inUserData) AUSDK_RTSAFE;\n\n\t//\tThis method is called (potentially repeatedly) by ProcessForScheduledParams()\n\t//\tin order to perform the actual DSP required for this portion of the entire buffer\n\t//\tbeing processed.  The entire buffer can be divided up into smaller \"slices\"\n\t//\taccording to the timestamps on the scheduled parameters...\n\t//\n\t//\tsub-classes wishing to handle scheduled parameter changes should override this method\n\t//  in order to do the appropriate DSP.  AUEffectBase already overrides this for standard\n\t//\teffect AudioUnits.\n\tvirtual OSStatus ProcessScheduledSlice(void* /*inUserData*/, UInt32 /*inStartFrameInBuffer*/,\n\t\tUInt32 /*inSliceFramesToProcess*/, UInt32 /*inTotalBufferFrames*/) AUSDK_RTSAFE\n\t{\n\t\t// default implementation does nothing.\n\t\treturn noErr;\n\t}\n\n\t[[nodiscard]] const AudioTimeStamp& CurrentRenderTime() const noexcept\n\t{\n\t\treturn mCurrentRenderTime;\n\t}\n\tvoid ResetRenderTime();\n\n\t// ________________________________________________________________________\n\t//\tPrivate data members to discourage hacking in subclasses\nprivate:\n\tstruct RenderCallback {\n\t\tRenderCallback() : RenderCallback(nullptr, nullptr) {}\n\n\t\tRenderCallback(AURenderCallback proc, void* ref)\n\t\t\t: mRenderNotify(proc), mRenderNotifyRefCon(ref)\n\t\t{\n\t\t}\n\n\t\tAURenderCallback mRenderNotify{ nullptr };\n\t\tvoid* mRenderNotifyRefCon{ nullptr };\n\n\t\tbool operator==(const RenderCallback& other) const\n\t\t{\n\t\t\treturn this->mRenderNotify == other.mRenderNotify &&\n\t\t\t\t   this->mRenderNotifyRefCon == other.mRenderNotifyRefCon;\n\t\t}\n\t};\n\nprotected:\n\tstatic constexpr AudioUnitScope kNumScopes = 4;\n\n\tParameterEventList& GetParamEventList() noexcept { return mParamEventList; }\n\tvoid SetBuffersAllocated(bool b) noexcept { mBuffersAllocated = b; }\n\n\t[[nodiscard]] CFStringRef GetContextName() const noexcept { return *mContextName; }\n\tvoid SetContextName(CFStringRef str) noexcept { mContextName = str; }\n\n\t[[nodiscard]] CFStringRef GetNickName() const noexcept { return *mNickName; }\n\nprivate:\n\tbool mElementsCreated{ false };\n\tbool mInitialized{ false };\n\tbool mHasBegunInitializing{ false };\n\tconst UInt32 mInitNumInputEls;\n\tconst UInt32 mInitNumOutputEls;\n\tconst UInt32 mInitNumGroupEls;\n\tstd::array<AUScope, kNumScopes> mScopes;\n\tAUThreadSafeList<RenderCallback> mRenderCallbacks;\n\tbool mRenderCallbacksTouched{ false };\n\tstd::thread::id mRenderThreadID{};\n\tbool mWantsRenderThreadID{ false };\n\tAudioTimeStamp mCurrentRenderTime{};\n\tUInt32 mMaxFramesPerSlice{ 0 };\n\tOSStatus mLastRenderError{ noErr };\n#ifndef AUSDK_NO_LOGGING\n\tconst double mHostTimeFrequency{\n\t\tHostTime::Frequency()\n\t}; // cache because there is calculation cost\n\tuint64_t mLastTimeMessagePrinted{ 0 };\n#endif\n\tAUPreset mCurrentPreset{ -1, nullptr };\n\tbool mUsesFixedBlockSize{ false };\n\n\tParameterEventList mParamEventList;\n\tPropertyListeners mPropertyListeners;\n\tbool mBuffersAllocated{ false };\n\tconst std::string mLogString;\n\tOwned<CFStringRef> mNickName;\n\n\t/*! @var mAUMutex\n\t\tIf non-null, guards all non-realtime entry points into the AudioUnit. Most AudioUnits\n\t\tdo not need to use this. It's useful for the case of an AU which must synchronize\n\t\tan external source of callbacks against entry from the host.\n\t*/\n\tAUMutex* mAUMutex{ nullptr };\n\tHostCallbackInfo mHostCallbackInfo{};\n\tOwned<CFStringRef> mContextName;\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUBase_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUBuffer.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUBuffer.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUBuffer_h\n#define AudioUnitSDK_AUBuffer_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <cstddef>\n#include <cstring>\n#include <optional>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/// struct created/destroyed by allocator. Do not attempt to manually create/destroy.\nstruct AllocatedBuffer {\n\tconst UInt32 mMaximumNumberBuffers;\n\tconst UInt32 mMaximumBytesPerBuffer;\n\tconst UInt32 mReservedA[2]{}; // NOLINT C-style array\n\tconst UInt32 mHeaderSize;\n\tconst UInt32 mBufferDataSize;\n\tconst UInt32 mReservedB[2]{}; // NOLINT C-style array\n\tvoid* const mBufferData;\n\tvoid* const mReservedC{};\n\n\tAudioBufferList mAudioBufferList{};\n\t// opaque variable-length data may follow the AudioBufferList\n\n\n\tAllocatedBuffer(UInt32 maxBuffers, UInt32 maxBytesPerBuffer, UInt32 headerSize,\n\t\tUInt32 bufferDataSize, void* bufferData)\n\t\t: mMaximumNumberBuffers{ maxBuffers }, mMaximumBytesPerBuffer{ maxBytesPerBuffer },\n\t\t  mHeaderSize{ headerSize }, mBufferDataSize{ bufferDataSize }, mBufferData{ bufferData }\n\t{\n\t}\n\n\tAudioBufferList& Prepare(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);\n\n\tExpectedPtr<AudioBufferList> PrepareOrError(\n\t\tUInt32 channelsPerBuffer, UInt32 bytesPerBuffer) AUSDK_RTSAFE;\n\n\tAudioBufferList& PrepareNull(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);\n\n\tExpectedPtr<AudioBufferList> PrepareNullOrError(\n\t\tUInt32 channelsPerBuffer, UInt32 bytesPerBuffer) AUSDK_RTSAFE;\n};\n\n/*!\n\t@class\tBufferAllocator\n\t@brief\tClass which allocates memory for internal audio buffers.\n\n\tTo customize, create a subclass and replace the BufferAllocator::instance() implementation.\n*/\nclass BufferAllocator {\npublic:\n\t/// Obtain the global instance, creating it if necessary.\n\tstatic BufferAllocator& instance();\n\n\tBufferAllocator() = default;\n\tvirtual ~BufferAllocator() = default;\n\n\t// Rule of 5\n\tBufferAllocator(const BufferAllocator&) = delete;\n\tBufferAllocator(BufferAllocator&&) = delete;\n\tBufferAllocator& operator=(const BufferAllocator&) = delete;\n\tBufferAllocator& operator=(BufferAllocator&&) = delete;\n\n\t// N.B. Must return zeroed memory aligned to at least 16 bytes.\n\tvirtual AllocatedBuffer* Allocate(\n\t\tUInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 reservedFlags);\n\tvirtual void Deallocate(AllocatedBuffer* allocatedBuffer);\n};\n\n/*!\n\t@class\tAUBufferList\n\t@brief\tManages an `AudioBufferList` backed by allocated memory buffers.\n*/\nclass AUBufferList {\n\tenum class EPtrState { Invalid, ToMyMemory, ToExternalMemory };\n\npublic:\n\tAUBufferList() = default;\n\t~AUBufferList() { Deallocate(); }\n\n\tAUBufferList(const AUBufferList&) = delete;\n\tAUBufferList(AUBufferList&&) = delete;\n\tAUBufferList& operator=(const AUBufferList&) = delete;\n\tAUBufferList& operator=(AUBufferList&&) = delete;\n\n\tAudioBufferList& PrepareBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames)\n\t{\n\t\tconst auto maybeABL = PrepareBufferOrError(format, nFrames);\n\t\tThrowExceptionIfUnexpected(maybeABL);\n\t\treturn *maybeABL;\n\t}\n\n\tExpectedPtr<AudioBufferList> PrepareBufferOrError(\n\t\tconst AudioStreamBasicDescription& format, UInt32 nFrames) AUSDK_RTSAFE;\n\n\tAudioBufferList& PrepareNullBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames)\n\t{\n\t\tconst auto maybeABL = PrepareNullBufferOrError(format, nFrames);\n\t\tThrowExceptionIfUnexpected(maybeABL);\n\t\treturn *maybeABL;\n\t}\n\n\tExpectedPtr<AudioBufferList> PrepareNullBufferOrError(\n\t\tconst AudioStreamBasicDescription& format, UInt32 nFrames) AUSDK_RTSAFE;\n\n\tAudioBufferList& SetBufferList(const AudioBufferList& abl)\n\t{\n\t\tconst auto maybeABL = SetBufferListOrError(abl);\n\t\tThrowExceptionIfUnexpected(maybeABL);\n\t\treturn *maybeABL;\n\t}\n\n\tExpectedPtr<AudioBufferList> SetBufferListOrError(const AudioBufferList& abl) AUSDK_RTSAFE\n\t{\n\t\tif (mAllocatedStreams < abl.mNumberBuffers) {\n\t\t\treturn Unexpected(-1);\n\t\t}\n\t\tmPtrState = EPtrState::ToExternalMemory;\n\t\tauto& myabl = mBuffers->mAudioBufferList;\n\t\tmemcpy(&myabl, &abl,\n\t\t\tstatic_cast<size_t>(\n\t\t\t\treinterpret_cast<const std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT\n\t\t\t\treinterpret_cast<const std::byte*>(&abl)));                             // NOLINT\n\t\treturn myabl;\n\t}\n\n\tvoid SetBuffer(UInt32 index, const AudioBuffer& ab)\n\t{\n\t\tconst auto res = SetBufferOrError(index, ab);\n\t\tThrowExceptionIfUnexpected(res);\n\t}\n\n\tExpected<void> SetBufferOrError(UInt32 index, const AudioBuffer& ab) AUSDK_RTSAFE\n\t{\n\t\tauto& myabl = mBuffers->mAudioBufferList;\n\t\tif (mPtrState == EPtrState::Invalid || index >= myabl.mNumberBuffers) {\n\t\t\treturn Unexpected(-1);\n\t\t}\n\t\tmPtrState = EPtrState::ToExternalMemory;\n\t\tmyabl.mBuffers[index] = ab; // NOLINT\n\t\treturn {};\n\t}\n\n\tvoid InvalidateBufferList() noexcept { mPtrState = EPtrState::Invalid; }\n\n\t[[nodiscard]] AudioBufferList& GetBufferList() const\n\t{\n\t\tconst auto maybeABL = GetBufferListOrError();\n\t\tThrowExceptionIfUnexpected(maybeABL);\n\t\treturn *maybeABL;\n\t}\n\n\t[[nodiscard]] ExpectedPtr<AudioBufferList> GetBufferListOrError() const AUSDK_RTSAFE\n\t{\n\t\tif (mPtrState == EPtrState::Invalid) {\n\t\t\treturn Unexpected(-1);\n\t\t}\n\t\treturn mBuffers->mAudioBufferList;\n\t}\n\n\tvoid CopyBufferListTo(AudioBufferList& abl) const\n\t{\n\t\tconst auto res = CopyBufferListToOrError(abl);\n\t\tThrowExceptionIfUnexpected(res);\n\t}\n\n\tExpected<void> CopyBufferListToOrError(AudioBufferList& abl) const AUSDK_RTSAFE\n\t{\n\t\tif (mPtrState == EPtrState::Invalid) {\n\t\t\treturn Unexpected(-1);\n\t\t}\n\t\tmemcpy(&abl, &mBuffers->mAudioBufferList,\n\t\t\tstatic_cast<size_t>(\n\t\t\t\treinterpret_cast<std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT\n\t\t\t\treinterpret_cast<std::byte*>(&abl)));                             // NOLINT\n\t\treturn {};\n\t}\n\n\tvoid CopyBufferContentsTo(AudioBufferList& destabl) const\n\t{\n\t\tconst auto res = CopyBufferContentsToOrError(destabl);\n\t\tThrowExceptionIfUnexpected(res);\n\t}\n\n\tExpected<void> CopyBufferContentsToOrError(AudioBufferList& destabl) const AUSDK_RTSAFE\n\t{\n\t\tif (mPtrState == EPtrState::Invalid) {\n\t\t\treturn Unexpected(-1);\n\t\t}\n\t\tconst auto& srcabl = mBuffers->mAudioBufferList;\n\t\tconst AudioBuffer* srcbuf = srcabl.mBuffers; // NOLINT\n\t\tAudioBuffer* destbuf = destabl.mBuffers;     // NOLINT\n\n\t\tfor (UInt32 i = 0; i < destabl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { // NOLINT\n\t\t\tif (i >=\n\t\t\t\tsrcabl.mNumberBuffers) { // duplicate last source to additional outputs [4341137]\n\t\t\t\t--srcbuf;                // NOLINT\n\t\t\t}\n\n\t\t\tconst auto srcByteSize = srcbuf->mDataByteSize;\n\t\t\tconst void* srcData = srcbuf->mData;\n\t\t\tvoid* dstData = destbuf->mData;\n\n\t\t\tif (srcByteSize > 0 && (srcData == nullptr || dstData == nullptr)) {\n\t\t\t\treturn Unexpected(-1);\n\t\t\t}\n\n\t\t\tif (dstData != srcData) {\n\t\t\t\tmemmove(dstData, srcData, srcByteSize);\n\t\t\t}\n\t\t\tdestbuf->mDataByteSize = srcByteSize;\n\t\t}\n\t\treturn {};\n\t}\n\n\tvoid Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames);\n\n\tvoid Deallocate();\n\n\t// AudioBufferList utilities\n\tstatic void ZeroBuffer(AudioBufferList& abl)\n\t{\n\t\tAudioBuffer* buf = abl.mBuffers;                         // NOLINT\n\t\tfor (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) { // NOLINT\n\t\t\tmemset(buf->mData, 0, buf->mDataByteSize);\n\t\t}\n\t}\n\n\t[[nodiscard]] UInt32 GetAllocatedFrames() const noexcept { return mAllocatedFrames; }\n\nprivate:\n\tEPtrState mPtrState{ EPtrState::Invalid };\n\tAllocatedBuffer* mBuffers = nullptr; // only valid between Allocate and Deallocate\n\n\tUInt32 mAllocatedStreams{ 0 };\n\tUInt32 mAllocatedFrames{ 0 };\n};\n\n} // namespace ausdk\n\nAUSDK_END_NO_RT_WARNINGS\n\n#endif // AudioUnitSDK_AUBuffer_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUConfig.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUConfig.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n\n#ifndef AudioUnitSDK_AUConfig_h\n#define AudioUnitSDK_AUConfig_h\n\n#include <TargetConditionals.h>\n\n#if defined(__has_include) && __has_include(<AvailabilityVersions.h>)\n#include <AvailabilityVersions.h>\n#endif\n\n#if defined(__has_include) && __has_include(<MacTypes.h>)\n#include <MacTypes.h>\n#else\nenum { noErr = 0 };\n#endif\n\n#if defined(__has_include) && __has_include(<CoreAudioTypes/CoreAudioTypes.h>)\n#include <CoreAudioTypes/CoreAudioTypes.h>\n#else\n#include <CoreAudio/CoreAudioTypes.h>\n#endif\n\n// This optional prefix header allows external customization of the build.\n#if defined(__has_include) && __has_include(\"AudioUnitSDKPrefix.h\")\n#include \"AudioUnitSDKPrefix.h\"\n#endif\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark Version\n\n#define AUSDK_VERSION_MAJOR 1\n#define AUSDK_VERSION_MINOR 4\n#define AUSDK_VERSION_PATCH 0\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark Deprecations\n\n#ifdef AUSDK_NO_DEPRECATIONS\n#define AUSDK_DEPRECATED(msg)\n#else\n#define AUSDK_DEPRECATED(msg) [[deprecated(msg)]] // NOLINT macro\n#endif                                            // AUSDK_NO_DEPRECATIONS\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark UI\n\n#if !defined(AUSDK_HAVE_UI)\n#define AUSDK_HAVE_UI 1\n#endif // !defined(AUSDK_HAVE_UI)\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark Mach\n\n#if !defined(AUSDK_HAVE_MACH_TIME)\n#if defined(__has_include) && __has_include(<mach/mach_time.h>)\n#define AUSDK_HAVE_MACH_TIME 1\n#else\n#define AUSDK_HAVE_MACH_TIME 0\n#endif\n#endif // !defined(AUSDK_HAVE_MACH_TIME)\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark MIDI\n\n#if !defined(AUSDK_HAVE_MIDI)\n#if defined(__has_include) && __has_include(<CoreMIDI/CoreMIDI.h>)\n#define AUSDK_HAVE_MIDI 1\n#else\n#define AUSDK_HAVE_MIDI 0\n#endif\n#endif // !defined(AUSDK_HAVE_MIDI)\n\n#if !defined(AUSDK_HAVE_MIDI2)\n#if defined(__MAC_12_0) || defined(__IPHONE_15_0)\n#define AUSDK_HAVE_MIDI2 (AUSDK_HAVE_MIDI)\n#else\n#define AUSDK_HAVE_MIDI2 0\n#endif\n#endif // !defined(AUSDK_HAVE_MIDI2)\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark MusicDevice\n\n#if !defined(AUSDK_HAVE_MUSIC_DEVICE)\n#if defined(__has_include) && __has_include(<AudioToolbox/MusicDevice.h>)\n#define AUSDK_HAVE_MUSIC_DEVICE 1\n#else\n#define AUSDK_HAVE_MUSIC_DEVICE 0\n#endif\n#endif // !defined(AUSDK_HAVE_MUSIC_DEVICE)\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark AudioOutputUnit\n\n#if !defined(AUSDK_HAVE_IO_UNITS)\n#if defined(__has_include) && __has_include(<AudioToolbox/AudioOutputUnit.h>)\n#define AUSDK_HAVE_IO_UNITS 1\n#else\n#define AUSDK_HAVE_IO_UNITS 0\n#endif\n#endif // !defined(AUSDK_HAVE_MUSIC_DEVICE)\n\n\n#endif /* AUConfig_h */\n"
  },
  {
    "path": "include/AudioUnitSDK/AUEffectBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUEffectBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUEffectBase_h\n#define AudioUnitSDK_AUEffectBase_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUSilentTimeout.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <memory>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\nclass AUKernelBase;\n\n/*!\n\t@class\tAUEffectBase\n\t@brief\tBase class for an effect with one input stream, one output stream, and any number of\n\t\t\tchannels.\n*/\nclass AUEffectBase : public AUBase {\npublic:\n\texplicit AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace = true);\n\n\tAUEffectBase(const AUEffectBase&) = delete;\n\tAUEffectBase(AUEffectBase&&) = delete;\n\tAUEffectBase& operator=(const AUEffectBase&) = delete;\n\tAUEffectBase& operator=(AUEffectBase&&) = delete;\n\n\t~AUEffectBase() override = default;\n\n\tOSStatus Initialize() override;\n\tvoid Cleanup() override;\n\tOSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement) override;\n\tOSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override;\n\tOSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData) override;\n\tOSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize) override;\n\tbool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override;\n\tOSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,\n\t\tconst AudioStreamBasicDescription& inPrevFormat,\n\t\tconst AudioStreamBasicDescription& inNewFormat) override;\n\tOSStatus Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,\n\t\tUInt32 nFrames) AUSDK_RTSAFE override;\n\n\t// If a kernel implements ResetRT, this can be used to reset with a realtime-safety assertion.\n\ttemplate <typename Kernel>\n\tOSStatus ResetRT(AudioUnitScope /*inScope*/, AudioUnitElement /*inElement*/) AUSDK_RTSAFE\n\t{\n\t\tfor (auto& kernel : mKernelList) {\n\t\t\tif (kernel) {\n\t\t\t\tstatic_cast<Kernel*>(kernel.get())->ResetRT();\n\t\t\t}\n\t\t}\n\t\t// Note that AUBase::Reset() is a no-op but not declared safe, so we bypass it.\n\t\treturn noErr;\n\t}\n\n\t// our virtual methods\n\n\t// If your unit processes N to N channels, and there are no interactions between channels,\n\t// it can override NewKernel to create a mono processing object per channel.  Otherwise,\n\t// don't override NewKernel, and instead, override ProcessBufferLists.\n\tvirtual std::unique_ptr<AUKernelBase> NewKernel() { return {}; }\n\tOSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioBufferList& inBuffer, AudioBufferList& outBuffer,\n\t\tUInt32 inFramesToProcess) AUSDK_RTSAFE override;\n\n\t// convenience format accessors (use output 0's format)\n\tFloat64 GetSampleRate() AUSDK_RTSAFE { return GetOutput0().GetStreamFormat().mSampleRate; }\n\tUInt32 GetNumberOfChannels() AUSDK_RTSAFE\n\t{\n\t\treturn GetOutput0().GetStreamFormat().mChannelsPerFrame;\n\t}\n\n\t// convenience wrappers for accessing parameters in the global scope\n\t// TODO: duplication with AUBase?\n\n\tusing AUBase::SetParameter;\n\n\tvoid SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value) AUSDK_RTSAFE\n\t{\n\t\tGlobals()->SetParameterRT(paramID, value);\n\t}\n\n\tusing AUBase::GetParameter;\n\n\tAudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) AUSDK_RTSAFE\n\t{\n\t\treturn Globals()->GetParameterRT(paramID);\n\t}\n\n\t[[nodiscard]] bool CanScheduleParameters() const AUSDK_RTSAFE override { return true; }\n\n\t// This is used for the property value - to reflect to the UI if an effect is bypassed\n\t[[nodiscard]] bool IsBypassEffect() const noexcept { return mBypassEffect; }\n\n\tvirtual void SetBypassEffect(bool inFlag) { mBypassEffect = inFlag; }\n\n\tvoid SetParamHasSampleRateDependency(bool inFlag) noexcept { mParamSRDep = inFlag; }\n\t[[nodiscard]] bool GetParamHasSampleRateDependency() const noexcept { return mParamSRDep; }\n\n\t/// Context, passed as `void* userData`, for `ProcessScheduledSlice()`.\n\tstruct ScheduledProcessParams {\n\t\tAudioUnitRenderActionFlags* actionFlags = nullptr;\n\t\tAudioBufferList* inputBufferList = nullptr;\n\t\tAudioBufferList* outputBufferList = nullptr;\n\t};\n\n\tOSStatus ProcessScheduledSlice(void* inUserData, UInt32 inStartFrameInBuffer,\n\t\tUInt32 inSliceFramesToProcess, UInt32 inTotalBufferFrames) AUSDK_RTSAFE override;\n\n\t[[nodiscard]] bool ProcessesInPlace() const noexcept { return mProcessesInPlace; }\n\tvoid SetProcessesInPlace(bool inProcessesInPlace) noexcept\n\t{\n\t\tmProcessesInPlace = inProcessesInPlace;\n\t}\n\n\tusing KernelList = std::vector<std::unique_ptr<AUKernelBase>>;\n\nprotected:\n\tvoid MaintainKernels();\n\n\t// This is used in the render call to see if an effect is bypassed\n\t// It can return a different status than IsBypassEffect (though it MUST take that into account)\n\tvirtual bool ShouldBypassEffect() AUSDK_RTSAFE { return IsBypassEffect(); }\n\n\t[[nodiscard]] AUKernelBase* GetKernel(UInt32 index) const\n\t{\n\t\treturn (index < mKernelList.size()) ? mKernelList[index].get() : nullptr;\n\t}\n\t[[nodiscard]] const KernelList& GetKernelList() const noexcept { return mKernelList; }\n\n\tbool IsInputSilent(AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess)\n\t{\n\t\tbool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0;\n\n\t\t// take latency and tail time into account when propagating the silent bit\n\t\tconst auto silentTimeoutFrames =\n\t\t\tstatic_cast<UInt32>(GetSampleRate() * (GetLatency() + GetTailTime()));\n\t\tmSilentTimeout.Process(inFramesToProcess, silentTimeoutFrames, inputSilent);\n\t\treturn inputSilent;\n\t}\n\n#if TARGET_OS_IPHONE\n\tvoid SetOnlyOneKernel(bool inUseOnlyOneKernel) noexcept\n\t{\n\t\tmOnlyOneKernel = inUseOnlyOneKernel;\n\t} // set in ctor of subclass that wants it.\n#endif\n\nprivate:\n\tKernelList mKernelList;\n\tbool mBypassEffect{ false };\n\tbool mParamSRDep{ false };\n\tbool mProcessesInPlace;\n\tAUSilentTimeout mSilentTimeout;\n\tAUOutputElement* mMainOutput{ nullptr };\n\tAUInputElement* mMainInput{ nullptr };\n\n#if TARGET_OS_IPHONE\n\tbool mOnlyOneKernel;\n#endif\n\tUInt32 mBytesPerFrame = 0;\n};\n\n\n/*!\n\t@class\tAUKernelBase\n\t@brief\tBase class for a signal-processing \"kernel\", an object that performs DSP on one channel\n\t\t\tof an audio stream.\n*/\nclass AUKernelBase {\npublic:\n\texplicit AUKernelBase(AUEffectBase& inAudioUnit) : mAudioUnit(inAudioUnit) {}\n\n\tAUSDK_DEPRECATED(\"Construct with a reference\")\n\texplicit AUKernelBase(AUEffectBase* inAudioUnit) : mAudioUnit(*inAudioUnit) {}\n\n\tAUKernelBase(const AUKernelBase&) = delete;\n\tAUKernelBase(AUKernelBase&&) = delete;\n\tAUKernelBase& operator=(const AUKernelBase&) = delete;\n\tAUKernelBase& operator=(AUKernelBase&&) = delete;\n\n\tvirtual ~AUKernelBase() = default;\n\n\tvirtual void Reset() {}\n\n\tvirtual void Process(const Float32* /*inSourceP*/, Float32* /*inDestP*/,\n\t\tUInt32 /*inFramesToProcess*/, bool& /*ioSilence*/) AUSDK_RTSAFE = 0;\n\n\tFloat64 GetSampleRate() AUSDK_RTSAFE { return mAudioUnit.GetSampleRate(); }\n\n\tAudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) AUSDK_RTSAFE\n\t{\n\t\treturn mAudioUnit.GetParameter(paramID);\n\t}\n\n\tvoid SetChannelNum(UInt32 inChan) noexcept { mChannelNum = inChan; }\n\t[[nodiscard]] UInt32 GetChannelNum() const noexcept { return mChannelNum; }\n\nprotected:\n\tAUEffectBase& mAudioUnit; // NOLINT protected\n\tUInt32 mChannelNum = 0;   // NOLINT protected\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUEffectBase_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUInputElement.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUInputElement.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUInputElement_h\n#define AudioUnitSDK_AUInputElement_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUScopeElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <AudioToolbox/AUComponent.h>\n#include <AudioToolbox/AudioUnitProperties.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/*!\n\t@class\tAUInputElement\n\t@brief\tImplements an audio unit input element, managing the source of input from a callback\n\t\t\tor connection.\n*/\nclass AUInputElement : public AUIOElement {\npublic:\n\tusing AUIOElement::AUIOElement;\n\n\t// AUElement override\n\tOSStatus SetStreamFormat(const AudioStreamBasicDescription& fmt) override;\n\t[[nodiscard]] bool NeedsBufferSpace() const override { return IsCallback(); }\n\tvoid SetConnection(const AudioUnitConnection& conn);\n\tvoid SetInputCallback(AURenderCallback proc, void* refCon);\n\t[[nodiscard]] bool IsActive() const noexcept { return mInputType != EInputType::NoInput; }\n\t[[nodiscard]] bool IsCallback() const noexcept\n\t{\n\t\treturn mInputType == EInputType::FromCallback;\n\t}\n\t[[nodiscard]] bool HasConnection() const noexcept\n\t{\n\t\treturn mInputType == EInputType::FromConnection;\n\t}\n\n\tOSStatus PullInput(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,\n\t\tAudioUnitElement inElement, UInt32 nFrames) AUSDK_RTSAFE;\n\n\tOSStatus PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags,\n\t\tconst AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames,\n\t\tAudioBufferList& inBufferList) AUSDK_RTSAFE;\n\nprotected:\n\tvoid Disconnect();\n\nprivate:\n\tenum class EInputType { NoInput, FromConnection, FromCallback };\n\tEInputType mInputType{ EInputType::NoInput };\n\n\t// if from callback:\n\tAURenderCallback mInputProc{ nullptr };\n\tvoid* mInputProcRefCon{ nullptr };\n\n\t// if from connection:\n\tAudioUnitConnection mConnection{};\n};\n\ninline OSStatus AUInputElement::PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames,\n\tAudioBufferList& inBufferList) AUSDK_RTSAFE\n{\n\tOSStatus theResult = noErr;\n\n\tif (HasConnection()) {\n\t\t// only support connections for V2 audio units\n\t\ttheResult = AudioUnitRender(mConnection.sourceAudioUnit, &ioActionFlags, &inTimeStamp,\n\t\t\tmConnection.sourceOutputNumber, nFrames, &inBufferList);\n\t} else {\n\t\t// kFromCallback:\n\t\ttheResult = (mInputProc)(mInputProcRefCon, &ioActionFlags, &inTimeStamp, inElement, nFrames,\n\t\t\t&inBufferList);\n\t}\n\n\t// defense: the upstream could have disconnected.\n\t// it's a horrible thing to do, but may happen!\n\tAUSDK_Require(mInputType != EInputType::NoInput, kAudioUnitErr_NoConnection);\n\n#if !TARGET_OS_IPHONE || DEBUG\n\tif (theResult == noErr) { // if there's already an error, there's no point (and maybe some harm)\n\t\t\t\t\t\t\t  // in validating.\n\t\tAUSDK_Require(\n\t\t\t!(ABL::IsBogusAudioBufferList(inBufferList) & 1), kAudioUnitErr_InvalidPropertyValue);\n\t}\n#endif\n\treturn theResult;\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUInputElement_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUMIDIBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUMIDIBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUMIDIBase_h\n#define AudioUnitSDK_AUMIDIBase_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n\n#ifndef AUSDK_HAVE_XML_NAMES\n#define AUSDK_HAVE_XML_NAMES TARGET_OS_OSX // NOLINT(cppcoreguidelines-macro-usage)\n#endif\n\n#ifndef AUSDK_HAVE_MIDI_MAPPING\n#define AUSDK_HAVE_MIDI_MAPPING TARGET_OS_OSX // NOLINT(cppcoreguidelines-macro-usage)\n#endif\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n#if AUSDK_HAVE_MIDI_MAPPING\n/// Abstract interface for parameter MIDI mapping\nclass AUMIDIMapper {\npublic:\n\tAUMIDIMapper() = default;\n\tvirtual ~AUMIDIMapper() = default;\n\n\tAUMIDIMapper(const AUMIDIMapper&) = delete;\n\tAUMIDIMapper(AUMIDIMapper&&) = delete;\n\tAUMIDIMapper& operator=(const AUMIDIMapper&) = delete;\n\tAUMIDIMapper& operator=(AUMIDIMapper&&) = delete;\n\n\t[[nodiscard]] virtual UInt32 GetNumberMaps() const = 0;\n\tvirtual void GetMaps(AUParameterMIDIMapping* outMapping) = 0;\n\tvirtual void GetHotParameterMap(AUParameterMIDIMapping& outMapping) = 0;\n\n\tvirtual void AddParameterMapping(\n\t\tconst AUParameterMIDIMapping* maps, UInt32 count, AUBase& auBase) = 0;\n\tvirtual void RemoveParameterMapping(\n\t\tconst AUParameterMIDIMapping* maps, UInt32 count, bool& outDidChange) = 0;\n\tvirtual void SetHotMapping(const AUParameterMIDIMapping& mapping) = 0;\n\tvirtual void ReplaceAllMaps(\n\t\tconst AUParameterMIDIMapping* maps, UInt32 count, AUBase& auBase) = 0;\n\n\tvirtual bool HandleHotMapping(\n\t\tUInt8 status, UInt8 channel, UInt8 data1, AUBase& auBase) AUSDK_RTSAFE = 0;\n\tvirtual bool FindParameterMapEventMatch(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2,\n\t\tUInt32 inStartFrame, AUBase& auBase) AUSDK_RTSAFE = 0;\n};\n#endif\n\n// ________________________________________________________________________\n//\tAUMIDIBase\n//\n/*!\n\t@class\tAUMIDIBase\n\t@brief\tAuxiliary class supporting MIDI events.\n*/\nclass AUMIDIBase {\npublic:\n\texplicit AUMIDIBase(AUBase& inBase) : mAUBaseInstance(inBase) {}\n\n\tvirtual ~AUMIDIBase() = default;\n\n\tAUMIDIBase(const AUMIDIBase&) = delete;\n\tAUMIDIBase(AUMIDIBase&&) = delete;\n\tAUMIDIBase& operator=(const AUMIDIBase&) = delete;\n\tAUMIDIBase& operator=(AUMIDIBase&&) = delete;\n\n\tvirtual OSStatus MIDIEvent(\n\t\tUInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) AUSDK_RTSAFE\n\t{\n\t\tconst auto strippedStatus = static_cast<UInt8>(inStatus & 0xf0U); // NOLINT\n\t\tconst auto channel = static_cast<UInt8>(inStatus & 0x0fU);        // NOLINT\n\n\t\treturn HandleMIDIEvent(strippedStatus, channel, inData1, inData2, inOffsetSampleFrame);\n\t}\n\n#if AUSDK_HAVE_MIDI2\n\tvirtual OSStatus MIDIEventList(\n\t\tUInt32 /*inOffsetSampleFrame*/, const MIDIEventList* /*eventList*/) AUSDK_RTSAFE\n\t{\n\t\treturn kAudio_UnimplementedError;\n\t}\n#endif\n\n\tvirtual OSStatus SysEx(const UInt8* inData, UInt32 inLength) AUSDK_RTSAFE;\n\n\tvirtual OSStatus DelegateGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable);\n\tvirtual OSStatus DelegateGetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData);\n\tvirtual OSStatus DelegateSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize);\n\nprotected:\n\t// MIDI dispatch\n\tvirtual OSStatus HandleMIDIEvent(UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2,\n\t\tUInt32 inStartFrame) AUSDK_RTSAFE;\n\tvirtual OSStatus HandleNonNoteEvent(\n\t\tUInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) AUSDK_RTSAFE;\n\n\t// Old name\n\tAUSDK_DEPRECATED(\"HandleMIDIEvent\")\n\tOSStatus HandleMidiEvent(UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2,\n\t\tUInt32 inStartFrame) AUSDK_RTSAFE\n\t{\n\t\treturn HandleMIDIEvent(inStatus, inChannel, inData1, inData2, inStartFrame);\n\t}\n\n#if AUSDK_HAVE_XML_NAMES\n\tvirtual OSStatus GetXMLNames(CFURLRef* /*outNameDocument*/)\n\t{\n\t\treturn kAudioUnitErr_InvalidProperty;\n\t} // if not overridden, it's unsupported\n#endif\n\n\t// channel messages\n\tvirtual OSStatus HandleNoteOn(UInt8 /*inChannel*/, UInt8 /*inNoteNumber*/, UInt8 /*inVelocity*/,\n\t\tUInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandleNoteOff(UInt8 /*inChannel*/, UInt8 /*inNoteNumber*/,\n\t\tUInt8 /*inVelocity*/, UInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandleControlChange(UInt8 /*inChannel*/, UInt8 /*inController*/,\n\t\tUInt8 /*inValue*/, UInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandlePitchWheel(UInt8 /*inChannel*/, UInt8 /*inPitch1*/, UInt8 /*inPitch2*/,\n\t\tUInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandleChannelPressure(\n\t\tUInt8 /*inChannel*/, UInt8 /*inValue*/, UInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandleProgramChange(UInt8 /*inChannel*/, UInt8 /*inValue*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandlePolyPressure(UInt8 /*inChannel*/, UInt8 /*inKey*/, UInt8 /*inValue*/,\n\t\tUInt32 /*inStartFrame*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\tvirtual OSStatus HandleResetAllControllers(UInt8 /*inChannel*/) AUSDK_RTSAFE { return noErr; }\n\tvirtual OSStatus HandleAllNotesOff(UInt8 /*inChannel*/) AUSDK_RTSAFE { return noErr; }\n\tvirtual OSStatus HandleAllSoundOff(UInt8 /*inChannel*/) AUSDK_RTSAFE { return noErr; }\n\n\t// System messages\n\tvirtual OSStatus HandleSysEx(const UInt8* /*inData*/, UInt32 /*inLength*/) AUSDK_RTSAFE\n\t{\n\t\treturn noErr;\n\t}\n\n#if AUSDK_HAVE_MIDI_MAPPING\n\tvoid SetMIDIMapper(const std::shared_ptr<AUMIDIMapper>& mapper) { mMIDIMapper = mapper; }\n#endif\n\nprivate:\n\tAUBase& mAUBaseInstance;\n#if AUSDK_HAVE_MIDI_MAPPING\n\tstd::shared_ptr<AUMIDIMapper> mMIDIMapper;\n#endif\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUMIDIBase_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUMIDIEffectBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUMIDIEffectBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUMIDIEffectBase_h\n#define AudioUnitSDK_AUMIDIEffectBase_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUEffectBase.h>\n#include <AudioUnitSDK/AUMIDIBase.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/*!\n\t@class\tAUMIDIEffectBase\n\t@brief\tSubclass of AUEffectBase and AUMIDIBase, providing an abstract base class for\n\t\t\tmusic effects.\n*/\nclass AUMIDIEffectBase : public AUEffectBase, public AUMIDIBase {\npublic:\n\texplicit AUMIDIEffectBase(AudioComponentInstance inInstance, bool inProcessesInPlace = false);\n\tOSStatus MIDIEvent(UInt32 inStatus, UInt32 inData1, UInt32 inData2,\n\t\tUInt32 inOffsetSampleFrame) AUSDK_RTSAFE override\n\t{\n\t\treturn AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);\n\t}\n\tOSStatus SysEx(const UInt8* inData, UInt32 inLength) AUSDK_RTSAFE override\n\t{\n\t\treturn AUMIDIBase::SysEx(inData, inLength);\n\t}\n\tOSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override;\n\tOSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData) override;\n\tOSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize) override;\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUMIDIEffectBase_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUMIDIUtility.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUMIDIUtility.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUMIDIUtility_h\n#define AudioUnitSDK_AUMIDIUtility_h\n\n#pragma message(\"This header is deprecated and will be removed in a future release.\")\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n\n#endif // AudioUnitSDK_AUMIDIUtility_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUOutputElement.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUOutputElement.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUOutputElement_h\n#define AudioUnitSDK_AUOutputElement_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUScopeElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\nnamespace ausdk {\n\nclass AUBase;\n\n/*!\n\t@class\tAUOutputElement\n\t@brief\tImplements an audio unit output element.\n*/\nclass AUOutputElement : public AUIOElement {\npublic:\n\texplicit AUOutputElement(AUBase& audioUnit);\n\n\tAUOutputElement(AUBase& audioUnit, const AudioStreamBasicDescription& format);\n\n\tAUSDK_DEPRECATED(\"Construct with a reference\")\n\texplicit AUOutputElement(AUBase* audioUnit) : AUOutputElement(*audioUnit) {}\n\n\t// AUElement override\n\tOSStatus SetStreamFormat(const AudioStreamBasicDescription& desc) override;\n\t[[nodiscard]] bool NeedsBufferSpace() const override { return true; }\n};\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUOutputElement_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUPlugInDispatch.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUPlugInDispatch.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUPlugInDispatch_h\n#define AudioUnitSDK_AUPlugInDispatch_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/ComponentBase.h>\n\nnamespace ausdk {\n\n/// Method lookup for a basic AUBase subclass.\nstruct AUBaseLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for a basic AUBase subclass.\ntemplate <class Implementor>\nclass AUBaseFactory : public APFactory<AUBaseLookup, Implementor> {};\n\n/// Method lookup for a AUBase subclass which implements I/O methods (Start, Stop).\nstruct AUOutputLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements I/O methods (Start, Stop).\ntemplate <class Implementor>\nclass AUOutputBaseFactory : public APFactory<AUOutputLookup, Implementor> {};\n\n/// Method lookup for an AUBase subclass which implements I/O methods (Start, Stop) and\n/// ComplexRender.\nstruct AUComplexOutputLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements I/O methods (Start, Stop) and ComplexRender.\ntemplate <class Implementor>\nclass AUOutputComplexBaseFactory : public APFactory<AUComplexOutputLookup, Implementor> {};\n\n/// Method lookup for an AUBase subclass which implements Process.\nstruct AUBaseProcessLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements Process.\ntemplate <class Implementor>\nclass AUBaseProcessFactory : public APFactory<AUBaseProcessLookup, Implementor> {};\n\n/// Method lookup for an AUBase subclass which implements ProcessMultiple.\nstruct AUBaseProcessMultipleLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements ProcessMultiple.\ntemplate <class Implementor>\nclass AUBaseProcessMultipleFactory : public APFactory<AUBaseProcessMultipleLookup, Implementor> {};\n\n/// Method lookup for an AUBase subclass which implements Process and ProcessMultiple.\nstruct AUBaseProcessAndMultipleLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements Process and ProcessMultiple.\ntemplate <class Implementor>\nclass AUBaseProcessAndMultipleFactory\n\t: public APFactory<AUBaseProcessAndMultipleLookup, Implementor> {};\n\n#if AUSDK_HAVE_MIDI\n/// Method lookup for an AUBase subclass which implements MusicDevice methods (MIDIEvent and SysEx).\nstruct AUMIDILookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements MusicDevice methods (MIDIEvent and SysEx).\ntemplate <class Implementor>\nclass AUMIDIEffectFactory : public APFactory<AUMIDILookup, Implementor> {};\n\n/// Method lookup for an AUBase subclass which implements Process and MusicDevice methods (MIDIEvent\n/// and SysEx).\nstruct AUMIDIProcessLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements Process and MusicDevice methods (MIDIEvent\n/// and SysEx).\ntemplate <class Implementor>\nclass AUMIDIProcessFactory : public APFactory<AUMIDIProcessLookup, Implementor> {};\n#endif // AUSDK_HAVE_MIDI\n\n#if AUSDK_HAVE_MUSIC_DEVICE\n/// Method lookup for an AUBase subclass which implements the full set of MusicDevice methods\n/// (MIDIEvent, SysEx, StartNote, StopNote).\nstruct AUMusicLookup {\n\tstatic AudioComponentMethod Lookup(SInt16 selector);\n};\n\n/// Factory for an AUBase subclass which implements the full set of MusicDevice methods\n/// (MIDIEvent, SysEx, StartNote, StopNote).\ntemplate <class Implementor>\nclass AUMusicDeviceFactory : public APFactory<AUMusicLookup, Implementor> {};\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUPlugInDispatch_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUScopeElement.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUScopeElement.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUScopeElement_h\n#define AudioUnitSDK_AUScopeElement_h\n\n// module\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/ComponentBase.h>\n\n// OS\n#include <AudioToolbox/AUComponent.h>\n\n// std\n#include <algorithm>\n#include <atomic>\n#include <memory>\n#include <utility>\n#include <vector>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\nclass AUBase;\n\n/// Wrap an atomic in a copy-constructible/assignable object. This allows storing atomic values in a\n/// vector (not directly possible since atomics are not copy-constructible/assignable).\ntemplate <typename T>\nclass AtomicValue {\npublic:\n\tAtomicValue() = default;\n\texplicit AtomicValue(T val) : mValue{ val } {}\n\t~AtomicValue() = default;\n\n\tAtomicValue(const AtomicValue& other) : mValue{ other.mValue.load() } {}\n\tAtomicValue(AtomicValue&& other) noexcept : mValue{ other.mValue.load() } {}\n\n\tAtomicValue& operator=(const AtomicValue& other)\n\t{\n\t\tif (&other != this) {\n\t\t\tmValue.store(other.mValue.load());\n\t\t}\n\t\treturn *this;\n\t}\n\n\tAtomicValue& operator=(AtomicValue&& other) noexcept\n\t{\n\t\tmValue.store(other.mValue.load());\n\t\treturn *this;\n\t}\n\n\tT load(std::memory_order m = std::memory_order_seq_cst) const { return mValue.load(m); }\n\tvoid store(T v, std::memory_order m = std::memory_order_seq_cst) { mValue.store(v, m); }\n\n\toperator T() const { return load(); } // NOLINT implicit conversions OK\n\n\tAtomicValue& operator=(T value)\n\t{\n\t\tstore(value);\n\t\treturn *this;\n\t}\n\nprivate:\n\tstd::atomic<T> mValue{};\n\tstatic_assert(decltype(mValue)::is_always_lock_free);\n};\n\n/// A bare-bones reinvention of boost::flat_map, just enough to hold parameters in sorted vectors.\ntemplate <typename Key, typename Value>\nclass flat_map {\n\tusing KVPair = std::pair<Key, Value>;\n\tusing Impl = std::vector<std::pair<Key, Value>>;\n\n\tstatic bool keyless(const KVPair& item, Key k) AUSDK_RTSAFE { return k > item.first; }\n\n\tImpl mImpl;\n\npublic:\n\tusing iterator = typename Impl::iterator;\n\tusing const_iterator = typename Impl::const_iterator;\n\n\t[[nodiscard]] bool empty() const noexcept { return mImpl.empty(); }\n\t[[nodiscard]] size_t size() const noexcept { return mImpl.size(); }\n\t[[nodiscard]] const_iterator begin() const noexcept { return mImpl.begin(); }\n\t[[nodiscard]] const_iterator end() const noexcept { return mImpl.end(); }\n\titerator begin() noexcept { return mImpl.begin(); }\n\titerator end() noexcept { return mImpl.end(); }\n\tconst_iterator cbegin() noexcept { return mImpl.cbegin(); }\n\tconst_iterator cend() noexcept { return mImpl.cend(); }\n\n\t[[nodiscard]] const_iterator lower_bound(Key k) const\n\t{\n\t\treturn std::lower_bound(mImpl.cbegin(), mImpl.cend(), k, RTSafeFP{ keyless });\n\t}\n\n\titerator lower_bound(Key k)\n\t{\n\t\treturn std::lower_bound(mImpl.begin(), mImpl.end(), k, RTSafeFP{ keyless });\n\t}\n\n\t[[nodiscard]] const_iterator find(Key k) const\n\t{\n\t\tauto iter = lower_bound(k);\n\t\tif (iter != mImpl.end()) {\n\t\t\tif (iter->first != k) {\n\t\t\t\titer = mImpl.end();\n\t\t\t}\n\t\t}\n\t\treturn iter;\n\t}\n\n\titerator find(Key k)\n\t{\n\t\tauto iter = lower_bound(k);\n\t\tif (iter != mImpl.end()) {\n\t\t\tif (iter->first != k) {\n\t\t\t\titer = mImpl.end();\n\t\t\t}\n\t\t}\n\t\treturn iter;\n\t}\n\n\tclass ItemProxy {\n\tpublic:\n\t\tItemProxy(flat_map& map, Key k) : mMap{ map }, mKey{ k } {}\n\n\t\toperator Value() const // NOLINT implicit conversion is OK\n\t\t{\n\t\t\tconst auto iter = mMap.find(mKey);\n\t\t\tif (iter == mMap.end()) {\n\t\t\t\tthrow std::runtime_error(\"Invalid map key\");\n\t\t\t}\n\t\t\treturn iter->second;\n\t\t}\n\n\t\tItemProxy& operator=(const Value& v)\n\t\t{\n\t\t\tconst auto iter = mMap.lower_bound(mKey);\n\t\t\tif (iter != mMap.end() && iter->first == mKey) {\n\t\t\t\titer->second = v;\n\t\t\t} else {\n\t\t\t\tmMap.mImpl.insert(iter, { mKey, v });\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\tflat_map& mMap;\n\t\tconst Key mKey;\n\t};\n\n\tItemProxy operator[](Key k) { return ItemProxy{ *this, k }; }\n};\n\n// ____________________________________________________________________________\n//\nclass AUIOElement;\n\n/// An organizational unit for parameters, with a name.\nclass AUElement {\npublic:\n\texplicit AUElement(AUBase& audioUnit) : mAudioUnit(audioUnit), mUseIndexedParameters(false) {}\n\n\tAUSDK_DEPRECATED(\"Construct with a reference\")\n\texplicit AUElement(AUBase* audioUnit) : AUElement(*audioUnit) {}\n\n\tAUElement(const AUElement&) = delete;\n\tAUElement(AUElement&&) = delete;\n\tAUElement& operator=(const AUElement&) = delete;\n\tAUElement& operator=(AUElement&&) = delete;\n\n\tvirtual ~AUElement() = default;\n\n\tvirtual UInt32 GetNumberOfParameters()\n\t{\n\t\treturn mUseIndexedParameters ? static_cast<UInt32>(mIndexedParameters.size())\n\t\t\t\t\t\t\t\t\t : static_cast<UInt32>(mParameters.size());\n\t}\n\tvirtual void GetParameterList(AudioUnitParameterID* outList);\n\t[[nodiscard]] bool HasParameterID(AudioUnitParameterID paramID) const AUSDK_RTSAFE;\n\n\t// Use this from the control (non-realtime) context. Throws if the parameter doesn't exist.\n\t[[nodiscard]] AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) const\n\t{\n\t\tconst auto res = GetParameterOrError(paramID);\n\t\tThrowExceptionIfUnexpected(res);\n\t\treturn *res;\n\t}\n\n\t// Use this from the render (realtime) context, when you are sure the parameter should exist.\n\t[[nodiscard]] AudioUnitParameterValue GetParameterRT(\n\t\tAudioUnitParameterID paramID) const AUSDK_RTSAFE\n\t{\n\t\tconst auto res = GetParameterOrError(paramID);\n\t\tAUSDK_Assert(res);\n\t\treturn *res;\n\t}\n\n\t// Primitive, returns an error if the parameter does not exist.\n\t[[nodiscard]] Expected<AudioUnitParameterValue> GetParameterOrError(\n\t\tAudioUnitParameterID paramID) const AUSDK_RTSAFE;\n\n\t// Use this from the control (non-realtime) context. Throws if the parameter doesn't exist.\n\t// Only set okWhenInitialized to true when you know the outside world cannot access this\n\t// element. Otherwise the parameter map could get corrupted.\n\tvoid SetParameter(\n\t\tAudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false)\n\t{\n\t\tconst auto res = SetParameterOrError(paramID, value, okWhenInitialized);\n\t\tThrowExceptionIfUnexpected(res);\n\t}\n\n\t// Use this from the render (realtime) context, when you are sure the parameter should exist.\n\tvoid SetParameterRT(AudioUnitParameterID paramID, AudioUnitParameterValue value,\n\t\tbool okWhenInitialized = false) AUSDK_RTSAFE\n\t{\n\t\tconst auto res = SetParameterOrError(paramID, value, okWhenInitialized);\n\t\tAUSDK_Assert(res);\n\t}\n\n\t// Primitive, returns an error if the parameter does not exist.\n\tExpected<void> SetParameterOrError(AudioUnitParameterID paramID, AudioUnitParameterValue value,\n\t\tbool okWhenInitialized = false) AUSDK_RTSAFE;\n\n\t// Only set okWhenInitialized to true when you know the outside world cannot access this\n\t// element. Otherwise the parameter map could get corrupted. N.B. This only handles\n\t// immediate parameters. Override to implement ramping. Called from\n\t// AUBase::ProcessForScheduledParams.\n\t[[nodiscard]] virtual OSStatus SetScheduledEvent(AudioUnitParameterID paramID,\n\t\tconst AudioUnitParameterEvent& inEvent, UInt32 inSliceOffsetInBuffer,\n\t\tUInt32 inSliceDurationFrames, bool okWhenInitialized = false) AUSDK_RTSAFE;\n\n\t[[nodiscard]] AUBase& GetAudioUnit() const noexcept { return mAudioUnit; }\n\n\tvoid SaveState(AudioUnitScope scope, CFMutableDataRef data);\n\tconst UInt8* RestoreState(const UInt8* state);\n\n\t[[nodiscard]] Owned<CFStringRef> GetName() const noexcept { return mElementName; }\n\tvoid SetName(CFStringRef inName) noexcept { mElementName = inName; }\n\n\t[[nodiscard]] bool HasName() const noexcept { return *mElementName != nullptr; }\n\n\tvirtual void UseIndexedParameters(UInt32 inNumberOfParameters);\n\n\tvirtual AUIOElement* AsIOElement() AUSDK_RTSAFE { return nullptr; }\n\nprivate:\n\tusing ParameterValue = AtomicValue<float>;\n\n\tAUBase& mAudioUnit;\n\tflat_map<AudioUnitParameterID, ParameterValue> mParameters;\n\tbool mUseIndexedParameters;\n\tstd::vector<ParameterValue> mIndexedParameters;\n\tOwned<CFStringRef> mElementName;\n};\n\n\n// ____________________________________________________________________________\n//\n\n/// A subclass of AUElement which represents an input or output bus, and has an associated\n/// audio format and buffers.\nclass AUIOElement : public AUElement {\npublic:\n\texplicit AUIOElement(AUBase& audioUnit);\n\n\tAUIOElement(AUBase& audioUnit, const AudioStreamBasicDescription& format)\n\t\t: AUIOElement{ audioUnit }\n\t{\n\t\tmStreamFormat = format;\n\t}\n\n\tAUSDK_DEPRECATED(\"Construct with a reference\")\n\texplicit AUIOElement(AUBase* audioUnit) : AUIOElement(*audioUnit) {}\n\n\t[[nodiscard]] const AudioStreamBasicDescription& GetStreamFormat() const noexcept\n\t{\n\t\treturn mStreamFormat;\n\t}\n\n\tvirtual OSStatus SetStreamFormat(const AudioStreamBasicDescription& format);\n\n\tvirtual void AllocateBuffer(UInt32 inFramesToAllocate = 0);\n\n\tvoid DeallocateBuffer();\n\n\t/// Determines (via subclass override) whether the element's buffer list needs to be allocated.\n\t[[nodiscard]] virtual bool NeedsBufferSpace() const = 0;\n\n\tvoid SetWillAllocateBuffer(bool inFlag) noexcept { mWillAllocate = inFlag; }\n\n\t[[nodiscard]] bool WillAllocateBuffer() const noexcept { return mWillAllocate; }\n\n\tAudioBufferList& PrepareBuffer(UInt32 nFrames)\n\t{\n\t\tif (mWillAllocate) {\n\t\t\treturn mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);\n\t\t}\n\t\tThrow(kAudioUnitErr_InvalidPropertyValue);\n\t}\n\n\tExpectedPtr<AudioBufferList> PrepareBufferOrError(UInt32 nFrames) AUSDK_RTSAFE\n\t{\n\t\tif (mWillAllocate) {\n\t\t\treturn mIOBuffer.PrepareBufferOrError(mStreamFormat, nFrames);\n\t\t}\n\t\treturn Unexpected(kAudioUnitErr_InvalidPropertyValue);\n\t}\n\n\tAudioBufferList& PrepareNullBuffer(UInt32 nFrames)\n\t{\n\t\treturn mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);\n\t}\n\n\tExpectedPtr<AudioBufferList> PrepareNullBufferOrError(UInt32 nFrames) AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.PrepareNullBufferOrError(mStreamFormat, nFrames);\n\t}\n\n\tAudioBufferList& SetBufferList(const AudioBufferList& abl)\n\t{\n\t\treturn mIOBuffer.SetBufferList(abl);\n\t}\n\n\tExpectedPtr<AudioBufferList> SetBufferListOrError(const AudioBufferList& abl) AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.SetBufferListOrError(abl);\n\t}\n\n\tvoid SetBuffer(UInt32 index, AudioBuffer& ab) { mIOBuffer.SetBuffer(index, ab); }\n\n\tExpected<void> SetBufferOrError(UInt32 index, AudioBuffer& ab) AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.SetBufferOrError(index, ab);\n\t}\n\n\tvoid InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); }\n\n\t[[nodiscard]] AudioBufferList& GetBufferList() const { return mIOBuffer.GetBufferList(); }\n\n\tExpectedPtr<AudioBufferList> GetBufferListOrError() const AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.GetBufferListOrError();\n\t}\n\n\t[[nodiscard]] float* GetFloat32ChannelData(UInt32 ch) const\n\t{\n\t\tconst auto& abl = GetBufferList();\n\t\tif (IsInterleaved()) {\n\t\t\treturn static_cast<float*>(abl.mBuffers[0].mData) + ch; // NOLINT\n\t\t}\n\t\treturn static_cast<float*>(abl.mBuffers[ch].mData); // NOLINT\n\t}\n\n\t// N.B. Returns null pointers on failure.\n\t[[nodiscard]] float* GetFloat32ChannelDataRT(UInt32 ch) const AUSDK_RTSAFE\n\t{\n\t\tconst auto abl = GetBufferListOrError();\n\t\tif (!abl) [[unlikely]] {\n\t\t\treturn nullptr;\n\t\t}\n\t\tif (IsInterleaved()) {\n\t\t\treturn static_cast<float*>(abl->mBuffers[0].mData) + ch; // NOLINT\n\t\t}\n\t\treturn static_cast<float*>(abl->mBuffers[ch].mData); // NOLINT\n\t}\n\n\tvoid CopyBufferListTo(AudioBufferList& abl) const { mIOBuffer.CopyBufferListTo(abl); }\n\tvoid CopyBufferContentsTo(AudioBufferList& abl) const { mIOBuffer.CopyBufferContentsTo(abl); }\n\n\tExpected<void> CopyBufferListToOrError(AudioBufferList& abl) const AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.CopyBufferListToOrError(abl);\n\t}\n\tExpected<void> CopyBufferContentsToOrError(AudioBufferList& abl) const AUSDK_RTSAFE\n\t{\n\t\treturn mIOBuffer.CopyBufferContentsToOrError(abl);\n\t}\n\n\t[[nodiscard]] bool IsInterleaved() const noexcept { return ASBD::IsInterleaved(mStreamFormat); }\n\t[[nodiscard]] UInt32 NumberChannels() const noexcept { return mStreamFormat.mChannelsPerFrame; }\n\t[[nodiscard]] UInt32 NumberInterleavedChannels() const noexcept\n\t{\n\t\treturn ASBD::NumberInterleavedChannels(mStreamFormat);\n\t}\n\tvirtual std::vector<AudioChannelLayoutTag> GetChannelLayoutTags();\n\n\t[[nodiscard]] const AUChannelLayout& ChannelLayout() const { return mChannelLayout; }\n\n\t// Old layout methods\n\tvirtual OSStatus SetAudioChannelLayout(const AudioChannelLayout& inLayout);\n\tvirtual UInt32 GetAudioChannelLayout(AudioChannelLayout* outLayoutPtr, bool& outWritable);\n\n\tvirtual OSStatus RemoveAudioChannelLayout();\n\n\t/*! @fn AsIOElement*/\n\tAUIOElement* AsIOElement() AUSDK_RTSAFE override { return this; }\n\nprotected:\n\tAUBufferList& IOBuffer() noexcept { return mIOBuffer; }\n\tvoid ForceSetAudioChannelLayout(const AudioChannelLayout& inLayout)\n\t{\n\t\tmChannelLayout = inLayout;\n\t}\n\nprivate:\n\tAudioStreamBasicDescription mStreamFormat{};\n\tAUChannelLayout mChannelLayout{};\n\tAUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed\n\t\t\t\t\t\t\t// for output: output cache, usually allocated early on\n\tbool mWillAllocate{ false };\n};\n\n// ____________________________________________________________________________\n//\n/*!\n\t@class\tAUScopeDelegate\n\t@brief\tProvides a way to customize a scope, thereby obtaining virtual scopes.\n\n\tCan be used to implement scopes with variable numbers of elements.\n*/\nclass AUScopeDelegate {\npublic:\n\tAUScopeDelegate() = default;\n\n\tvirtual ~AUScopeDelegate() = default;\n\n\tAUScopeDelegate(const AUScopeDelegate&) = delete;\n\tAUScopeDelegate(AUScopeDelegate&&) = delete;\n\tAUScopeDelegate& operator=(const AUScopeDelegate&) = delete;\n\tAUScopeDelegate& operator=(AUScopeDelegate&&) = delete;\n\n\tvoid Initialize(AUBase* creator, AudioUnitScope scope, UInt32 numElements)\n\t{\n\t\tmCreator = creator;\n\t\tmScope = scope;\n\t\tSetNumberOfElements(numElements);\n\t}\n\tvirtual void SetNumberOfElements(UInt32 numElements) = 0;\n\tvirtual UInt32 GetNumberOfElements() AUSDK_RTSAFE = 0;\n\tvirtual AUElement* GetElement(UInt32 elementIndex) AUSDK_RTSAFE = 0;\n\n\t[[nodiscard]] AUBase* GetCreator() const noexcept { return mCreator; }\n\t[[nodiscard]] AudioUnitScope GetScope() const noexcept { return mScope; }\n\n\nprivate:\n\tAUBase* mCreator{ nullptr };\n\tAudioUnitScope mScope{ 0 };\n};\n\n// ____________________________________________________________________________\n//\n/*!\n\t@class\tAUScope\n\t@brief\tOrganizes one or more elements into an addressable group (e.g. global, input, output).\n*/\nclass AUScope {\npublic:\n\tAUScope() = default;\n\n\t~AUScope() = default;\n\n\tAUScope(const AUScope&) = delete;\n\tAUScope(AUScope&&) = delete;\n\tAUScope& operator=(const AUScope&) = delete;\n\tAUScope& operator=(AUScope&&) = delete;\n\n\tvoid Initialize(AUBase* creator, AudioUnitScope scope, UInt32 numElements)\n\t{\n\t\tmCreator = creator;\n\t\tmScope = scope;\n\n\t\tif (mDelegate != nullptr) {\n\t\t\treturn mDelegate->Initialize(creator, scope, numElements);\n\t\t}\n\n\t\tSetNumberOfElements(numElements);\n\t}\n\tvoid SetNumberOfElements(UInt32 numElements);\n\n\t[[nodiscard]] UInt32 GetNumberOfElements() const\n\t{\n\t\tif (mDelegate != nullptr) {\n\t\t\treturn mDelegate->GetNumberOfElements();\n\t\t}\n\t\treturn static_cast<UInt32>(mElements.size());\n\t}\n\n\t[[nodiscard]] AUElement* GetElement(UInt32 elementIndex) const AUSDK_RTSAFE\n\t{\n\t\tif (mDelegate != nullptr) {\n\t\t\treturn mDelegate->GetElement(elementIndex);\n\t\t}\n\t\treturn elementIndex < mElements.size() ? mElements[elementIndex].get() : nullptr;\n\t}\n\t[[nodiscard]] AUElement* SafeGetElement(UInt32 elementIndex) const\n\t{\n\t\tAUElement* const element = GetElement(elementIndex);\n\t\tausdk::ThrowExceptionIf(element == nullptr, kAudioUnitErr_InvalidElement);\n\t\treturn element;\n\t}\n\t[[nodiscard]] AUIOElement* GetIOElement(UInt32 elementIndex) const\n\t{\n\t\tAUElement* const element = GetElement(elementIndex);\n\t\tAUIOElement* const ioel = element != nullptr ? element->AsIOElement() : nullptr;\n\t\tausdk::ThrowExceptionIf(ioel == nullptr, kAudioUnitErr_InvalidElement);\n\t\treturn ioel;\n\t}\n\n\ttemplate <typename Elem = AUElement>\n\t[[nodiscard]] ExpectedPtr<Elem> GetElementOrError(UInt32 elementIndex) const AUSDK_RTSAFE\n\t{\n\t\tif (mDelegate != nullptr) {\n\t\t\tif (auto* elem = mDelegate->GetElement(elementIndex)) {\n\t\t\t\treturn *static_cast<Elem*>(elem);\n\t\t\t}\n\t\t} else if (elementIndex < mElements.size()) {\n\t\t\tif (auto* elem = mElements[elementIndex].get()) {\n\t\t\t\treturn *static_cast<Elem*>(elem);\n\t\t\t}\n\t\t}\n\t\treturn Unexpected(kAudioUnitErr_InvalidElement);\n\t}\n\n\t[[nodiscard]] ExpectedPtr<AUIOElement> GetIOElementOrError(UInt32 elementIndex) const\n\t{\n\t\tauto& element = AUSDK_UnwrapOrReturnUnexpected(GetElementOrError(elementIndex));\n\t\tif (AUIOElement* const ioel = element.AsIOElement()) {\n\t\t\treturn *ioel;\n\t\t}\n\t\treturn Unexpected(kAudioUnitErr_InvalidElement);\n\t}\n\n\t[[nodiscard]] bool HasElementWithName() const;\n\tvoid AddElementNamesToDict(CFMutableDictionaryRef inNameDict) const;\n\n\t[[nodiscard]] std::vector<AudioUnitElement> RestoreElementNames(\n\t\tCFDictionaryRef inNameDict) const;\n\n\t[[nodiscard]] AudioUnitScope GetScope() const noexcept { return mScope; }\n\n\tvoid SetDelegate(AUScopeDelegate* inDelegate) noexcept { mDelegate = inDelegate; }\n\tvoid SaveState(CFMutableDataRef data) const;\n\tconst UInt8* RestoreState(const UInt8* state) const;\n\nprivate:\n\tusing ElementVector = std::vector<std::unique_ptr<AUElement>>;\n\n\tAUBase* mCreator{ nullptr };\n\tAudioUnitScope mScope{ 0 };\n\tElementVector mElements;\n\tAUScopeDelegate* mDelegate{ nullptr };\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUScopeElement_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUSilentTimeout.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUSilentTimeout.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUSilentTimeout_h\n#define AudioUnitSDK_AUSilentTimeout_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n\n#include <CoreFoundation/CFBase.h> // for UInt32\n\n#include <algorithm>\n\nnamespace ausdk {\n\n/*!\n\t@class\tAUSilentTimeout\n\t@brief\tUtility to assist in propagating a silence flag from signal-processing\n\t\t\tinput to output, factoring in a processing delay.\n*/\nclass AUSilentTimeout {\npublic:\n\tAUSilentTimeout() = default;\n\n\tvoid Process(UInt32 inFramesToProcess, UInt32 inTimeoutLimit, bool& ioSilence)\n\t{\n\t\tif (ioSilence) {\n\t\t\tif (mResetTimer) {\n\t\t\t\tmTimeoutCounter = inTimeoutLimit;\n\t\t\t\tmResetTimer = false;\n\t\t\t}\n\n\t\t\tif (mTimeoutCounter > 0) {\n\t\t\t\tmTimeoutCounter -= std::min(inFramesToProcess, mTimeoutCounter);\n\t\t\t\tioSilence = false;\n\t\t\t}\n\t\t} else {\n\t\t\t// signal to reset the next time we receive silence\n\t\t\tmResetTimer = true;\n\t\t}\n\t}\n\n\tvoid Reset() { mResetTimer = true; }\n\nprivate:\n\tUInt32 mTimeoutCounter{ 0 };\n\tbool mResetTimer{ false };\n};\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUSilentTimeout_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUThreadSafeList.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUThreadSafeList.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUThreadSafeList_h\n#define AudioUnitSDK_AUThreadSafeList_h\n\n// module\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUUtility.h>\n\n// std\n#include <atomic>\n#include <concepts>\n#include <type_traits>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/*!\n\t@class\tAUAtomicStack\n\t@brief\tLinked list LIFO or FIFO (popAllReversed) stack, elements are pushed and popped\n\t\t\tatomically.\n */\n#ifdef __cpp_lib_concepts\ntemplate <std::default_initializable T>\n#else\ntemplate <typename T, std::enable_if_t<std::is_default_constructible_v<T>, bool> = true>\n#endif\nclass AUAtomicStack {\npublic:\n\tAUAtomicStack() = default;\n\n\t// Non-atomic routines, for use when initializing/deinitializing, operate NON-atomically\n\tvoid PushNonAtomic(T* item) noexcept\n\t{\n\t\titem->Next() = mHead;\n\t\tmHead = item;\n\t}\n\n\tT* PopNonAtomic() noexcept\n\t{\n\t\tT* result = mHead;\n\t\tif (result)\n\t\t\tmHead = result->Next();\n\t\treturn result;\n\t}\n\n\t// Atomic routines\n\tvoid PushAtomic(T* item) noexcept\n\t{\n\t\tT* head_{};\n\t\tdo {\n\t\t\thead_ = mHead;\n\t\t\titem->Next() = head_;\n\t\t} while (!CompareAndSwap(head_, item));\n\t}\n\n\t// Pushes entire linked list headed by item\n\tvoid PushMultipleAtomic(T* item) noexcept\n\t{\n\t\tT *head_{}, *p = item, *tail{};\n\t\t// Find the last one -- when done, it will be linked to head\n\t\tdo {\n\t\t\ttail = p;\n\t\t\tp = p->Next();\n\t\t} while (p);\n\t\tdo {\n\t\t\thead_ = mHead;\n\t\t\ttail->Next() = head_;\n\t\t} while (!CompareAndSwap(head_, item));\n\t}\n\n\t// This may only be used when only one thread may potentially pop from the stack.\n\t// if multiple threads may pop, this suffers from the ABA problem.\n\tT* PopAtomicSingleReader() noexcept\n\t{\n\t\tT* result{};\n\t\tdo {\n\t\t\tif ((result = mHead) == nullptr)\n\t\t\t\tbreak;\n\t\t} while (!CompareAndSwap(result, result->Next()));\n\t\treturn result;\n\t}\n\n\t// This is inefficient for large linked lists.\n\t// prefer PopAll() to a series of calls to PopAtomic.\n\t// PushMultipleAtomic has to traverse the entire list.\n\tT* PopAtomic() noexcept\n\t{\n\t\tT* result = PopAll();\n\t\tif (result) {\n\t\t\tT* next = result->Next();\n\t\t\tif (next)\n\t\t\t\t// push all the remaining items back onto the stack\n\t\t\t\tPushMultipleAtomic(next);\n\t\t}\n\t\treturn result;\n\t}\n\n\tT* PopAll() noexcept\n\t{\n\t\tT* result{};\n\t\tdo {\n\t\t\tif ((result = mHead) == nullptr)\n\t\t\t\tbreak;\n\t\t} while (!CompareAndSwap(result, nullptr));\n\t\treturn result;\n\t}\n\n\tT* PopAllReversed() noexcept\n\t{\n\t\tAUAtomicStack<T> reversed;\n\t\tT* p = PopAll();\n\t\twhile (p != nullptr) {\n\t\t\tT* next = p->Next();\n\t\t\treversed.PushNonAtomic(p);\n\t\t\tp = next;\n\t\t}\n\t\treturn reversed.mHead;\n\t}\n\n\tbool CompareAndSwap(T* oldvalue, T* newvalue) noexcept\n\t{\n\t\treturn std::atomic_compare_exchange_strong_explicit(\n\t\t\t&mHead, &oldvalue, newvalue, std::memory_order_seq_cst, std::memory_order_relaxed);\n\t}\n\n\t[[nodiscard]] bool empty() const noexcept { return mHead == nullptr; }\n\n\tT* head() const noexcept { return mHead; }\n\n\tvoid SetHead(T* newHead) { this->mHead.store(newHead); }\n\nprotected:\n\tstd::atomic<T*> mHead{ nullptr };\n\tstatic_assert(decltype(mHead)::is_always_lock_free);\n};\n\n// -------------------------------------------------------------------------------------------------\n/*!\n @class    AUThreadSafeList\n @brief    A thread-safe linked list.\n */\ntemplate <class T>\nclass AUThreadSafeList {\npublic:\n\tenum class EventType { Unknown, Add, Remove, Clear };\n\n\tclass Node {\n\tpublic:\n\t\tNode* mNext{ nullptr };\n\t\tEventType mEventType{ EventType::Unknown };\n\t\tT mObject{};\n\n\t\tNode*& Next() { return mNext; }\n\t};\n\tusing NodeStack = AUAtomicStack<Node>;\n\n\tclass iterator {\n\tpublic:\n\t\titerator() {}\n\t\titerator(Node* n) : mNode(n) {}\n\n\t\tbool operator==(const iterator& other) const { return this->mNode == other.mNode; }\n\t\tbool operator!=(const iterator& other) const { return this->mNode != other.mNode; }\n\n\t\tT& operator*() const { return mNode->mObject; }\n\n\t\titerator& operator++()\n\t\t{\n\t\t\tmNode = mNode->Next();\n\t\t\treturn *this;\n\t\t} // preincrement\n\n\t\titerator operator++(int)\n\t\t{\n\t\t\titerator tmp = *this;\n\t\t\tmNode = mNode->next();\n\t\t\treturn tmp;\n\t\t} // postincrement\n\n\t\tusing iterator_category = std::forward_iterator_tag;\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing value_type = T;\n\t\tusing reference = T&;\n\t\tusing pointer = T*;\n\n\tprivate:\n\t\tNode* mNode{ nullptr };\n\t};\n\n\tAUThreadSafeList() = default;\n\t~AUThreadSafeList()\n\t{\n\t\tFreeAll(mActiveList);\n\t\tFreeAll(mPendingList);\n\t\tFreeAll(mFreeList);\n\t}\n\n\tAUThreadSafeList(const AUThreadSafeList&) = delete;\n\tAUThreadSafeList(AUThreadSafeList&&) = delete;\n\tAUThreadSafeList& operator=(const AUThreadSafeList&) = delete;\n\tAUThreadSafeList& operator=(AUThreadSafeList&&) = delete;\n\n\t// These may be called on any thread\n\tvoid Add(const T& obj)\n\t{\n\t\tNode* node = AllocNode();\n\t\tnode->mEventType = EventType::Add;\n\t\tnode->mObject = obj;\n\t\tmPendingList.PushAtomic(node);\n\t}\n\n\t// can be called on any thread\n\tvoid Remove(const T& obj)\n\t{\n\t\tNode* node = AllocNode();\n\t\tnode->mEventType = EventType::Remove;\n\t\tnode->mObject = obj;\n\t\tmPendingList.PushAtomic(node);\n\t}\n\n\tvoid Clear() // can be called on any thread\n\t{\n\t\tNode* node = AllocNode();\n\t\tnode->mEventType = EventType::Clear;\n\t\tmPendingList.PushAtomic(node);\n\t}\n\n\t// These must be called from only one thread\n\tvoid Update() AUSDK_RTSAFE\n\t{\n\t\tNodeStack reversed;\n\t\tNode* event{};\n\t\tbool workDone = false;\n\n\t\t// reverse the events so they are in order\n\t\tevent = mPendingList.PopAll();\n\t\twhile (event != nullptr) {\n\t\t\tNode* next = event->mNext;\n\t\t\treversed.PushNonAtomic(event);\n\t\t\tevent = next;\n\t\t\tworkDone = true;\n\t\t}\n\n\t\tif (workDone) {\n\t\t\t// now process them\n\t\t\twhile ((event = reversed.PopNonAtomic()) != nullptr) {\n\t\t\t\tswitch (event->mEventType) {\n\t\t\t\tcase EventType::Add: {\n\t\t\t\t\tNode* endNode{};\n\t\t\t\t\tbool needToInsert = true;\n\t\t\t\t\tfor (Node* node = mActiveList.head(); node != nullptr; node = node->mNext) {\n\t\t\t\t\t\tif (node->mObject == event->mObject) {\n\t\t\t\t\t\t\tFreeNode(event);\n\t\t\t\t\t\t\tneedToInsert = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tendNode = node;\n\t\t\t\t\t}\n\t\t\t\t\tif (needToInsert) {\n\t\t\t\t\t\t// link the new event in at the end of the active list\n\t\t\t\t\t\tif (!endNode) {\n\t\t\t\t\t\t\tmActiveList.PushNonAtomic(event);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tendNode->Next() = event;\n\t\t\t\t\t\t\tevent->mNext = nullptr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} break;\n\t\t\t\tcase EventType::Remove: {\n\t\t\t\t\t// find matching node in the active list, remove it\n\t\t\t\t\tNode* previousNode{};\n\t\t\t\t\tfor (Node* node = mActiveList.head(); node != nullptr; node = node->mNext) {\n\t\t\t\t\t\tif (node->mObject == event->mObject) {\n\t\t\t\t\t\t\tif (!previousNode) {\n\t\t\t\t\t\t\t\tmActiveList.SetHead(node->mNext);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tpreviousNode->Next() = node->mNext; // remove from linked list\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tFreeNode(node);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpreviousNode = node;\n\t\t\t\t\t}\n\n\t\t\t\t\t// dispose the request node\n\t\t\t\t\tFreeNode(event);\n\t\t\t\t} break;\n\t\t\t\tcase EventType::Clear: {\n\t\t\t\t\tNode* next{};\n\t\t\t\t\tfor (Node* node = mActiveList.head(); node != nullptr;) {\n\t\t\t\t\t\tnext = node->mNext;\n\t\t\t\t\t\tFreeNode(node);\n\t\t\t\t\t\tnode = next;\n\t\t\t\t\t}\n\t\t\t\t\tFreeNode(event);\n\n\t\t\t\t\tif (mActiveList.head()) {\n\t\t\t\t\t\tmActiveList.SetHead(nullptr);\n\t\t\t\t\t}\n\t\t\t\t} break;\n\t\t\t\tdefault:\n\t\t\t\t\tAUSDK_LogError_RT(\"Unknown AUThreadSafeList event type\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\titerator begin() const noexcept { return iterator(mActiveList.head()); }\n\titerator end() const noexcept { return iterator(nullptr); }\n\nprivate:\n\tNode* AllocNode()\n\t{\n\t\tNode* node = mFreeList.PopAtomic();\n\t\tif (node == nullptr)\n\t\t\tnode = new Node();\n\t\treturn node;\n\t}\n\n\tvoid FreeNode(Node* node) { mFreeList.PushAtomic(node); }\n\tstatic void FreeAll(AUAtomicStack<Node>& stack)\n\t{\n\t\tNode* node{};\n\t\twhile ((node = stack.PopNonAtomic()) != nullptr) {\n\t\t\tdelete node;\n\t\t}\n\t}\n\n\tNodeStack mActiveList;  // what's actually in the container - only accessed on one thread\n\tNodeStack mPendingList; // add or remove requests - threadsafe\n\tNodeStack mFreeList;    // free nodes for reuse - threadsafe\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUThreadSafeList_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AUUtility.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUUtility.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_AUUtility_h\n#define AudioUnitSDK_AUUtility_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n\n// OS\n#include <CoreFoundation/CFByteOrder.h>\n\n#if AUSDK_HAVE_MACH_TIME\n#include <mach/mach_time.h>\n#endif\n\n// std\n#include <bitset>\n#include <climits>\n#include <cstdlib>\n#include <cstring>\n#include <expected>\n#include <memory>\n#include <mutex>\n#include <span>\n#include <stdexcept>\n#include <string>\n#include <system_error>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark Error-handling macros\n\n#ifndef AUSDK_LOG_OBJECT\n#define AUSDK_LOG_OBJECT OS_LOG_DEFAULT // NOLINT macro\n#endif                                  // AUSDK_LOG_OBJECT\n\n#ifdef AUSDK_NO_LOGGING\n#define AUSDK_LogError(...) /* NOLINT macro */\n#else\n#include <os/log.h>\n#include <syslog.h>\n#define AUSDK_LogError(...) /* NOLINT macro */                                                     \\\n\tif (__builtin_available(macOS 10.11, *)) {                                                     \\\n\t\tos_log_error(AUSDK_LOG_OBJECT, __VA_ARGS__);                                               \\\n\t} else {                                                                                       \\\n\t\tsyslog(LOG_ERR, __VA_ARGS__);                                                              \\\n\t}\n#endif\n\n// logging from realtime thread\n#define AUSDK_LogError_RT(...) AUSDK_RT_UNSAFE(AUSDK_LogError(__VA_ARGS__)) /* NOLINT macro */\n\n#define AUSDK_Catch(result) /* NOLINT(cppcoreguidelines-macro-usage) */                            \\\n\tcatch (const ausdk::AUException& exc) { (result) = exc.mError; }                               \\\n\tcatch (const std::bad_alloc&) { (result) = kAudio_MemFullError; }                              \\\n\tcatch (const OSStatus& catch_err) { (result) = catch_err; }                                    \\\n\tcatch (const std::system_error& exc) { (result) = exc.code().value(); }                        \\\n\tcatch (...) { (result) = -1; }\n\n#define AUSDK_Require(expr, error) /* NOLINT(cppcoreguidelines-macro-usage) */                     \\\n\tdo {                                                                                           \\\n\t\tif (!(expr)) {                                                                             \\\n\t\t\treturn error;                                                                          \\\n\t\t}                                                                                          \\\n\t} while (0) /* NOLINT */\n\n// Check an expected; if it holds an error, return that error.\n#define AUSDK_RequireExpected(exp) /* NOLINT(cppcoreguidelines-macro-usage) */                     \\\n\tAUSDK_Require(exp, exp.error())\n\n// Evaluate an expression resulting in an Expected<T>. If the Expected contains an error, return\n// the error. Otherwise, unwrap the Expected.\n#define AUSDK_UnwrapOrReturnError(_expression)                                                     \\\n\t*({                                                                                            \\\n\t\tconst auto e = (_expression);                                                              \\\n\t\tif (!e) [[unlikely]]                                                                       \\\n\t\t\treturn e.error();                                                                      \\\n\t\te;                                                                                         \\\n\t})\n\n// TODO: deprecate this macro because it swallows the error\n#define AUSDK_UnwrapOrReturnVoid(_expression)                                                      \\\n\t*({                                                                                            \\\n\t\tconst auto e = (_expression);                                                              \\\n\t\tif (!e) [[unlikely]]                                                                       \\\n\t\t\treturn;                                                                                \\\n\t\te;                                                                                         \\\n\t})\n\n#define AUSDK_CheckReturnError(_expression)                                                        \\\n\t({                                                                                             \\\n\t\tconst auto e = (_expression);                                                              \\\n\t\tif (!e) [[unlikely]]                                                                       \\\n\t\t\treturn e.error();                                                                      \\\n\t})\n\n// Evaluate an expression resulting in an Expected<T>. If the Expected contains an error, return\n// the error as an Unexpected. Otherwise, unwrap the Expected.\n#define AUSDK_UnwrapOrReturnUnexpected(_expression)                                                \\\n\t*({                                                                                            \\\n\t\tconst auto e = (_expression);                                                              \\\n\t\tif (!e) [[unlikely]]                                                                       \\\n\t\t\treturn ausdk::Unexpected{ e.error() };                                                 \\\n\t\te;                                                                                         \\\n\t})\n\n#define AUSDK_Require_noerr(_expression) /* NOLINT(cppcoreguidelines-macro-usage) */               \\\n\tdo {                                                                                           \\\n\t\tconst auto status_tmp_macro_detail_ = (_expression);                                       \\\n\t\tif (status_tmp_macro_detail_ != noErr) [[unlikely]] {                                      \\\n\t\t\treturn status_tmp_macro_detail_;                                                       \\\n\t\t}                                                                                          \\\n\t} while (0)\n\n#define AUSDK_Assert(_expression)                                                                  \\\n\t({                                                                                             \\\n\t\tconst auto e = (_expression);                                                              \\\n\t\tif (!e) [[unlikely]]                                                                       \\\n\t\t\tstd::abort();                                                                          \\\n\t})\n\n\n// clang-format off\n\n// The \"loose\" realtime-safety contract: exceptions are allowed.\n#ifndef AUSDK_LOOSE_RT_SAFETY\n\t#define AUSDK_LOOSE_RT_SAFETY 1\n#endif\n\n// AUSDK adopts `noexcept` independently of `[[clang::nonblocking]]`; suppress diagnostics.\n#define AUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS \\\n\t_Pragma(\"clang diagnostic push\")                                           \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wunknown-warning-option\\\"\")           \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wperf-constraint-implies-noexcept\\\"\")\n#define AUSDK_END_NO_RT_NOEXCEPT_WARNINGS  \\\n\t_Pragma(\"clang diagnostic pop\")\n\n//  ASAN inserts blocking function calls in otherwise nonblocking functions.\n#if defined(__has_feature) && __has_feature(address_sanitizer)\n#define AUSDK_BEGIN_NO_RT_WARNINGS                                              \\\n    AUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS                                         \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wfunction-effects\\\"\")\n#else\n#define AUSDK_BEGIN_NO_RT_WARNINGS                                              \\\n    AUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS\n#endif\n\n#define AUSDK_END_NO_RT_WARNINGS                                                \\\n    AUSDK_END_NO_RT_NOEXCEPT_WARNINGS\n\n/*!\n\t@macro\tAUSDK_RTSAFE_TYPE\n\t@brief\tA function type which is guaranteed / required to be realtime safe.\n*/\n#if defined(__has_attribute) && __has_attribute(nonblocking)\n#  ifdef __cplusplus\n#    define AUSDK_RTSAFE_TYPE [[clang::nonblocking]]\n#  else\n#    define AUSDK_RTSAFE_TYPE __attribute__((nonblocking))\n#  endif\n#else\n#    define AUSDK_RTSAFE_TYPE\n#endif\n\n#ifndef AUSDK_RTSAFE_SECTION\n#  define AUSDK_RTSAFE_SECTION\n#endif\n\n/*!\n\t@macro\tAUSDK_RTSAFE\n\t@brief\tDeclares a function as `nonblocking`, with a section attribute.\n\t\n\tExample placement:\n\t\t`void func(int param) AUSDK_RTSAFE;`\n*/\n#define AUSDK_RTSAFE AUSDK_RTSAFE_TYPE AUSDK_RTSAFE_SECTION\n\n#if AUSDK_LOOSE_RT_SAFETY\n\t#define AUSDK_RTSAFE_LOOSE AUSDK_RTSAFE\n#else\n\t#define AUSDK_RTSAFE_LOOSE\n#endif\n\n/*!\n\t@macro\tAUSDK_RTSAFE_LAMBDA\n\t@brief\tDeclares a lambda as `nonblocking`, with a section attribute.\n\t\n\tExample placement:\n\t\t`auto lambda = [captures](int param) AUSDK_RTSAFE_LAMBDA -> int { ... };`\n\t\n\tNote: It's weird and annoying that this has to be different from `AUSDK_RTSAFE`.\n*/\n#define AUSDK_RTSAFE_LAMBDA AUSDK_RTSAFE_SECTION AUSDK_RTSAFE_TYPE\n\n/*!\n\t@macro\tAUSDK_RT_UNSAFE_BEGIN\n\t@brief\tBegins a region of code as exempt from nonblocking checks.\n\n\tN.B. Every use of this is a maintenance and safety liability; use as a last resort.\n*/\n#define AUSDK_RT_UNSAFE_BEGIN(reason)                                \\\n\t_Pragma(\"clang diagnostic push\")                                 \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wunknown-warning-option\\\"\") \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wfunction-effects\\\"\")\n\n/*!\n\t@macro\tAUSDK_RT_UNSAFE_END\n\t@brief\tEnds a region of code which is exempt from nonblocking checks.\n*/\n#define AUSDK_RT_UNSAFE_END \\\n\t_Pragma(\"clang diagnostic pop\")\n\n/*!\n\t@macro\tAUSDK_RT_UNSAFE_END\n\t@brief\tDisables nonblocking checks during the evaluation of the expression.\n\n\tN.B. Every use of this is a maintenance and safety liability; use as a last resort.\n*/\n#define AUSDK_RT_UNSAFE(...)                                         \\\n\t_Pragma(\"clang diagnostic push\")                                 \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wunknown-warning-option\\\"\") \\\n\t_Pragma(\"clang diagnostic ignored \\\"-Wfunction-effects\\\"\")       \\\n\t__VA_ARGS__                                                      \\\n\t_Pragma(\"clang diagnostic pop\")\n\n// clang-format on\n\n#pragma mark -\n\n// -------------------------------------------------------------------------------------------------\n\nnamespace ausdk {\n\n// -------------------------------------------------------------------------------------------------\n\n/// A wrapper to preserve the nonblocking attribute on a function pointer. Copied from the\n/// nonblocking proposal.\ntemplate <typename>\nclass RTSafeFP;\n\ntemplate <typename R, typename... Args>\nclass RTSafeFP<R(Args...)> {\npublic:\n\tusing impl_t = R (*)(Args...) AUSDK_RTSAFE_TYPE;\n\nprivate:\n\timpl_t mImpl;\n\npublic:\n\tRTSafeFP(impl_t f) : mImpl{ f } {}\n\n\tR operator()(Args... args) const { return mImpl(std::forward<Args>(args)...); }\n};\n\n// deduction guide (copied from std::function)\ntemplate <class R, class... ArgTypes>\nRTSafeFP(R (*)(ArgTypes...)) -> RTSafeFP<R(ArgTypes...)>;\n\n// -------------------------------------------------------------------------------------------------\n\n/// A subclass of std::runtime_error that holds an OSStatus error.\nclass AUException : public std::runtime_error {\npublic:\n\texplicit AUException(OSStatus err)\n\t\t: std::runtime_error{ std::string(\"OSStatus \") + std::to_string(err) }, mError{ err }\n\t{\n\t}\n\n\tconst OSStatus mError;\n};\n\nAUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS\n[[noreturn]] inline void Throw(OSStatus err) AUSDK_RTSAFE_LOOSE\n{\n\tAUSDK_RT_UNSAFE_BEGIN(\"Can only log and throw under loose contract\")\n\tAUSDK_LogError(\"throwing %d\", static_cast<int>(err));\n\tthrow AUException{ err };\n\tAUSDK_RT_UNSAFE_END\n}\nAUSDK_END_NO_RT_NOEXCEPT_WARNINGS\n\ninline void ThrowExceptionIf(bool condition, OSStatus err)\n{\n\tif (condition) [[unlikely]] {\n\t\tThrow(err);\n\t}\n}\n\nAUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS\n[[noreturn]] inline void ThrowQuiet(OSStatus err) AUSDK_RTSAFE_LOOSE\n{\n\tAUSDK_RT_UNSAFE_BEGIN(\"Can only throw under loose realtime contract\")\n\tthrow AUException{ err };\n\tAUSDK_RT_UNSAFE_END\n}\nAUSDK_END_NO_RT_NOEXCEPT_WARNINGS\n\ninline void ThrowQuietIf(bool condition, OSStatus err)\n{\n\tif (condition) [[unlikely]] {\n\t\tThrowQuiet(err);\n\t}\n}\n\n// -------------------------------------------------------------------------------------------------\n\n/// Wrap a std::recursive_mutex in a C++ Mutex (named requirement). Methods are virtual to support\n/// customization.\nclass AUMutex {\npublic:\n\tAUMutex() = default;\n\tvirtual ~AUMutex() = default;\n\n\tAUMutex(const AUMutex&) = delete;\n\tAUMutex(AUMutex&&) = delete;\n\tAUMutex& operator=(const AUMutex&) = delete;\n\tAUMutex& operator=(AUMutex&&) = delete;\n\n\tvirtual void lock() { mImpl.lock(); }\n\tvirtual void unlock() noexcept { mImpl.unlock(); }\n\tvirtual bool try_lock() noexcept { return mImpl.try_lock(); }\n\nprivate:\n\tstd::recursive_mutex mImpl;\n};\n\n// -------------------------------------------------------------------------------------------------\n\n/// Implement optional locking at AudioUnit non-realtime entry points (required only for a small\n/// number of plug-ins which must synchronize against external entry points).\nclass AUEntryGuard {\npublic:\n\texplicit AUEntryGuard(AUMutex* maybeMutex) : mMutex{ maybeMutex }\n\t{\n\t\tif (mMutex != nullptr) {\n\t\t\tmMutex->lock();\n\t\t}\n\t}\n\n\t~AUEntryGuard() noexcept\n\t{\n\t\tif (mMutex != nullptr) {\n\t\t\tmMutex->unlock();\n\t\t}\n\t}\n\n\tAUEntryGuard(const AUEntryGuard&) = delete;\n\tAUEntryGuard(AUEntryGuard&&) = delete;\n\tAUEntryGuard& operator=(const AUEntryGuard&) = delete;\n\tAUEntryGuard& operator=(AUEntryGuard&&) = delete;\n\nprivate:\n\tAUMutex* mMutex;\n};\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark ASBD\n\n/// Utility functions relating to AudioStreamBasicDescription.\nnamespace ASBD {\n\nconstexpr bool IsInterleaved(const AudioStreamBasicDescription& format) noexcept\n{\n\treturn (format.mFormatFlags & kLinearPCMFormatFlagIsNonInterleaved) == 0u;\n}\n\nconstexpr UInt32 NumberInterleavedChannels(const AudioStreamBasicDescription& format) noexcept\n{\n\treturn IsInterleaved(format) ? format.mChannelsPerFrame : 1;\n}\n\nconstexpr UInt32 NumberChannelStreams(const AudioStreamBasicDescription& format) noexcept\n{\n\treturn IsInterleaved(format) ? 1 : format.mChannelsPerFrame;\n}\n\nconstexpr bool IsCommonFloat32(const AudioStreamBasicDescription& format) noexcept\n{\n\treturn (\n\t\tformat.mFormatID == kAudioFormatLinearPCM && format.mFramesPerPacket == 1 &&\n\t\tformat.mBytesPerPacket == format.mBytesPerFrame\n\t\t// so far, it's a valid PCM format\n\t\t&& (format.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0 &&\n\t\t(format.mChannelsPerFrame == 1 ||\n\t\t\t(format.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) &&\n\t\t((format.mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian) &&\n\t\tformat.mBitsPerChannel == 32 // NOLINT\n\t\t&& format.mBytesPerFrame == NumberInterleavedChannels(format) * sizeof(float));\n}\n\nconstexpr AudioStreamBasicDescription CreateCommonFloat32(\n\tFloat64 sampleRate, UInt32 numChannels, bool interleaved = false) noexcept\n{\n\tconstexpr auto sampleSize = sizeof(Float32);\n\n\tAudioStreamBasicDescription asbd{};\n\tasbd.mFormatID = kAudioFormatLinearPCM;\n\tasbd.mFormatFlags = kAudioFormatFlagIsFloat |\n\t\t\t\t\t\tstatic_cast<AudioFormatFlags>(kAudioFormatFlagsNativeEndian) |\n\t\t\t\t\t\tkAudioFormatFlagIsPacked;\n\tasbd.mBitsPerChannel = 8 * sampleSize; // NOLINT magic number\n\tasbd.mChannelsPerFrame = numChannels;\n\tasbd.mFramesPerPacket = 1;\n\tasbd.mSampleRate = sampleRate;\n\tif (interleaved) {\n\t\tasbd.mBytesPerPacket = asbd.mBytesPerFrame = numChannels * sampleSize;\n\t} else {\n\t\tasbd.mBytesPerPacket = asbd.mBytesPerFrame = sampleSize;\n\t\tasbd.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;\n\t}\n\treturn asbd;\n}\n\nconstexpr bool MinimalSafetyCheck(const AudioStreamBasicDescription& x) noexcept\n{\n\t// This function returns false if there are sufficiently unreasonable values in any field.\n\t// It is very conservative so even some very unlikely values will pass.\n\t// This is just meant to catch the case where the data from a file is corrupted.\n\n\treturn (x.mSampleRate >= 0.) && (x.mSampleRate < 3e6) // NOLINT SACD sample rate is 2.8224 MHz\n\t\t   && (x.mBytesPerPacket < 1000000)               // NOLINT\n\t\t   && (x.mFramesPerPacket < 1000000)              // NOLINT\n\t\t   && (x.mBytesPerFrame < 1000000)                // NOLINT\n\t\t   && (x.mChannelsPerFrame > 0) && (x.mChannelsPerFrame <= 1024) // NOLINT\n\t\t   && (x.mBitsPerChannel <= 1024)                                // NOLINT\n\t\t   && (x.mFormatID != 0) &&\n\t\t   !(x.mFormatID == kAudioFormatLinearPCM &&\n\t\t\t   (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame));\n}\n\ninline bool IsEqual(\n\tconst AudioStreamBasicDescription& lhs, const AudioStreamBasicDescription& rhs) noexcept\n{\n\treturn memcmp(&lhs, &rhs, sizeof(AudioStreamBasicDescription)) == 0;\n}\n\n} // namespace ASBD\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark ACL\n\n/// Utility functions relating to AudioChannelLayout.\nnamespace ACL {\n\nconstexpr bool operator==(const AudioChannelLayout& lhs, const AudioChannelLayout& rhs) noexcept\n{\n\tif (lhs.mChannelLayoutTag != rhs.mChannelLayoutTag) {\n\t\treturn false;\n\t}\n\tif (lhs.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {\n\t\treturn lhs.mChannelBitmap == rhs.mChannelBitmap;\n\t}\n\tif (lhs.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {\n\t\tif (lhs.mNumberChannelDescriptions != rhs.mNumberChannelDescriptions) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (UInt32 i = 0; i < lhs.mNumberChannelDescriptions; ++i) {\n\t\t\tconst auto& lhdesc = lhs.mChannelDescriptions[i]; // NOLINT array subscript\n\t\t\tconst auto& rhdesc = rhs.mChannelDescriptions[i]; // NOLINT array subscript\n\n\t\t\tif (lhdesc.mChannelLabel != rhdesc.mChannelLabel) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (lhdesc.mChannelLabel == kAudioChannelLabel_UseCoordinates) {\n\t\t\t\tif (memcmp(&lhdesc, &rhdesc, sizeof(AudioChannelDescription)) != 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n} // namespace ACL\n\n// -------------------------------------------------------------------------------------------------\n\n/// Utility wrapper for the variably-sized AudioChannelLayout struct.\nclass AUChannelLayout {\npublic:\n\tAUChannelLayout() : AUChannelLayout(0, kAudioChannelLayoutTag_UseChannelDescriptions, 0) {}\n\n\t/// Can construct from a layout tag.\n\texplicit AUChannelLayout(AudioChannelLayoutTag inTag) : AUChannelLayout(0, inTag, 0) {}\n\n\tAUChannelLayout(uint32_t inNumberChannelDescriptions, AudioChannelLayoutTag inChannelLayoutTag,\n\t\tAudioChannelBitmap inChannelBitMap)\n\t\t: mStorage(ObjectCountForByteSize(DataByteSize(inNumberChannelDescriptions)))\n\t{\n\t\tauto& acl = mStorage.front();\n\t\tacl.mChannelLayoutTag = inChannelLayoutTag;\n\t\tacl.mChannelBitmap = inChannelBitMap;\n\t\tacl.mNumberChannelDescriptions = inNumberChannelDescriptions;\n\t}\n\n\t/// Implicit conversion from AudioChannelLayout& is allowed.\n\tAUChannelLayout(const AudioChannelLayout& acl) // NOLINT\n\t\t: mStorage(ObjectCountForByteSize(DataByteSize(acl.mNumberChannelDescriptions)))\n\t{\n\t\tstd::memcpy(mStorage.data(), &acl, DataByteSize(acl.mNumberChannelDescriptions));\n\t}\n\n\t~AUChannelLayout() noexcept = default;\n\tAUChannelLayout(AUChannelLayout&&) noexcept = default;\n\tAUChannelLayout& operator=(AUChannelLayout&&) noexcept = default;\n\n\t// copy overloads required because AudioChannelLayout deletes them\n\tAUChannelLayout(const AUChannelLayout& other) { CopyStorage(other); }\n\n\tAUChannelLayout& operator=(const AUChannelLayout& other)\n\t{\n\t\tCopyStorage(other);\n\t\treturn *this;\n\t}\n\n\tbool operator==(const AUChannelLayout& other) const noexcept\n\t{\n\t\treturn ACL::operator==(Layout(), other.Layout());\n\t}\n\n\tbool operator!=(const AUChannelLayout& other) const noexcept { return !(*this == other); }\n\n\t[[nodiscard]] bool IsValid() const noexcept { return NumberChannels() > 0; }\n\n\t[[nodiscard]] const AudioChannelLayout& Layout() const noexcept { return mStorage.front(); }\n\n\t[[nodiscard]] const AudioChannelLayout* LayoutPtr() const noexcept { return mStorage.data(); }\n\n\t/// After default construction, this method will return\n\t/// kAudioChannelLayoutTag_UseChannelDescriptions with 0 channel descriptions.\n\t[[nodiscard]] AudioChannelLayoutTag Tag() const noexcept { return Layout().mChannelLayoutTag; }\n\n\t[[nodiscard]] uint32_t NumberChannels() const noexcept { return NumberChannels(Layout()); }\n\n\t[[nodiscard]] uint32_t Size() const noexcept\n\t{\n\t\treturn static_cast<uint32_t>(DataByteSize(Layout().mNumberChannelDescriptions));\n\t}\n\n\tstatic uint32_t NumberChannels(const AudioChannelLayout& inLayout) noexcept\n\t{\n\t\tif (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {\n\t\t\treturn inLayout.mNumberChannelDescriptions;\n\t\t}\n\t\tif (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {\n\t\t\tconstexpr size_t bitWidth = sizeof(inLayout.mChannelBitmap) * CHAR_BIT;\n\t\t\treturn static_cast<uint32_t>(std::bitset<bitWidth>(inLayout.mChannelBitmap).count());\n\t\t}\n\t\treturn AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag);\n\t}\n\n\tstatic constexpr size_t DataByteSize(uint32_t inNumberChannelDescriptions) noexcept\n\t{\n\t\tconstexpr size_t headerSize = offsetof(AudioChannelLayout, mChannelDescriptions);\n\t\treturn headerSize + (inNumberChannelDescriptions * sizeof(AudioChannelDescription));\n\t}\n\nprivate:\n\t// number of contiguous ACL objects required to accommodate a specific storage size\n\tstatic constexpr size_t ObjectCountForByteSize(size_t inDataByteSize) noexcept\n\t{\n\t\tconst size_t padding = ((inDataByteSize % sizeof(AudioChannelLayout)) > 0) ? 1 : 0;\n\t\treturn (inDataByteSize / sizeof(AudioChannelLayout)) + padding;\n\t}\n\n\tvoid CopyStorage(const AUChannelLayout& inSource)\n\t{\n\t\tmStorage = decltype(mStorage)(inSource.mStorage.size());\n\t\tstd::memcpy(\n\t\t\tmStorage.data(), inSource.mStorage.data(), std::span(inSource.mStorage).size_bytes());\n\t}\n\n\t// the data representation is not literally an array of these entire objects, however using it\n\t// as the underlying storage data type ensures object lifetime and alignment of the data pointer\n\tstd::vector<AudioChannelLayout> mStorage;\n};\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark AudioBufferList\n\n/// Utility functions relating to AudioBufferList.\nnamespace ABL {\n\n// if the return result is odd, there was a null buffer.\nconstexpr uint32_t IsBogusAudioBufferList(const AudioBufferList& abl)\n{\n\tconst AudioBuffer *buf = abl.mBuffers, *const bufEnd = buf + abl.mNumberBuffers;\n\tuint32_t sum =\n\t\t0; // defeat attempts by the compiler to optimize away the code that touches the buffers\n\tuint32_t anyNull = 0;\n\tfor (; buf < bufEnd; ++buf) {\n\t\tconst uint32_t* const p = static_cast<const uint32_t*>(buf->mData);\n\t\tif (p == nullptr) {\n\t\t\tanyNull = 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst auto dataSize = buf->mDataByteSize;\n\t\tif (dataSize >= sizeof(*p)) {\n\t\t\tconst size_t frameCount = dataSize / sizeof(*p);\n\t\t\tsum += p[0];\n\t\t\tsum += p[frameCount - 1];\n\t\t}\n\t}\n\treturn anyNull | (sum & ~1u);\n}\n\n} // namespace ABL\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n#pragma mark HostTime\n\n#if AUSDK_HAVE_MACH_TIME\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n/// Utility functions relating to Mach absolute time.\nnamespace HostTime {\n\n/// Returns the current host time\ninline uint64_t Current() AUSDK_RTSAFE { return AUSDK_RT_UNSAFE(mach_absolute_time()); }\n\n/// Returns the frequency of the host timebase, in ticks per second.\ninline double Frequency()\n{\n\tstruct mach_timebase_info timeBaseInfo {}; // NOLINT\n\tmach_timebase_info(&timeBaseInfo);\n\t//\tthe frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9\n\treturn static_cast<double>(timeBaseInfo.denom) / static_cast<double>(timeBaseInfo.numer) *\n\t\t   1.0e9; // NOLINT\n}\n\n} // namespace HostTime\nAUSDK_END_NO_RT_WARNINGS\n#endif // AUSDK_HAVE_MACH_TIME\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n\n/// Basic RAII wrapper for CoreFoundation types\ntemplate <typename T>\n\trequires std::is_pointer_v<T>\nclass Owned {\n\texplicit Owned(T obj, bool fromget) noexcept : mImpl{ obj }\n\t{\n\t\tif (fromget) {\n\t\t\tretainRef();\n\t\t}\n\t}\n\npublic:\n\tstatic Owned from_get(T obj) noexcept { return Owned{ obj, true }; }\n\n\tstatic Owned from_create(T obj) noexcept { return Owned{ obj, false }; }\n\tstatic Owned from_copy(T obj) noexcept { return Owned{ obj, false }; }\n\n\tOwned() noexcept = default;\n\t~Owned() noexcept { releaseRef(); }\n\n\tOwned(const Owned& other) noexcept : mImpl{ other.mImpl } { retainRef(); }\n\n\tOwned(Owned&& other) noexcept : mImpl{ std::exchange(other.mImpl, nullptr) } {}\n\n\tOwned& operator=(const Owned& other) noexcept\n\t{\n\t\tif (this != &other) {\n\t\t\treleaseRef();\n\t\t\tmImpl = other.mImpl;\n\t\t\tretainRef();\n\t\t}\n\t\treturn *this;\n\t}\n\n\tOwned& operator=(Owned&& other) noexcept\n\t{\n\t\tstd::swap(mImpl, other.mImpl);\n\t\treturn *this;\n\t}\n\n\tT operator*() const noexcept { return get(); }\n\tT get() const noexcept { return mImpl; }\n\n\t/// As with `unique_ptr<T>::release()`, releases ownership of the reference to the caller (not\n\t/// to be confused with decrementing the reference count as with `CFRelease()`).\n\tT release() noexcept { return std::exchange(mImpl, nullptr); }\n\n\t/// This is a from_get operation.\n\tOwned& operator=(T cfobj) noexcept\n\t{\n\t\tif (mImpl != cfobj) {\n\t\t\treleaseRef();\n\t\t\tmImpl = cfobj;\n\t\t\tretainRef();\n\t\t}\n\t\treturn *this;\n\t}\n\nprivate:\n\tvoid retainRef() noexcept\n\t{\n\t\tif (mImpl != nullptr) {\n\t\t\tCFRetain(mImpl);\n\t\t}\n\t}\n\n\tvoid releaseRef() noexcept\n\t{\n\t\tif (mImpl != nullptr) {\n\t\t\tCFRelease(mImpl);\n\t\t}\n\t}\n\n\tT mImpl{ nullptr };\n};\n\n// -------------------------------------------------------------------------------------------------\n#pragma mark -\n\ntemplate <typename T>\nconcept TriviallyCopySerializable = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;\n\n// copy object data to arbitrary memory address that may not share object alignment\nvoid Serialize(const TriviallyCopySerializable auto& inValue, void* outData) noexcept\n{\n\tstd::memcpy(outData, std::addressof(inValue), sizeof(inValue));\n}\n\ntemplate <TriviallyCopySerializable T, std::size_t Extent>\nvoid Serialize(std::span<T, Extent> inValues, void* outData) noexcept\n{\n\tstd::memcpy(outData, inValues.data(), inValues.size_bytes());\n}\n\n// ensure object lifetime and alignment of object data from opaque pointer\ntemplate <TriviallyCopySerializable T>\n\trequires std::is_nothrow_default_constructible_v<T> && (!std::is_const_v<T>)\nT Deserialize(const void* inData) noexcept\n{\n\tT result{};\n\tstd::memcpy(std::addressof(result), inData, sizeof(result));\n\treturn result;\n}\n\ntemplate <TriviallyCopySerializable T>\n\trequires std::is_default_constructible_v<T> && (!std::is_const_v<T>)\nstd::vector<T> DeserializeArray(const void* inData, size_t inSizeBytes)\n{\n\tstd::vector<T> result(inSizeBytes / sizeof(T));\n\tstd::memcpy(result.data(), inData, std::span(result).size_bytes());\n\treturn result;\n}\n\ninline UInt32 DeserializeBigUInt32AndAdvance(const UInt8*& ioData) noexcept\n{\n\tconst auto value = Deserialize<UInt32>(ioData);\n\tioData += sizeof(value); // NOLINT\n\treturn CFSwapInt32BigToHost(value);\n}\n\ninline std::string MakeStringFrom4CC(uint32_t in4CC)\n{\n\tin4CC = CFSwapInt32HostToBig(in4CC);\n\n\tconstexpr auto safeIsPrint = [](char character) {\n\t\treturn (character >= ' ') && (character <= '~');\n\t};\n\n\tchar* const string = reinterpret_cast<char*>(&in4CC); // NOLINT\n\tfor (size_t i = 0; i < sizeof(in4CC); ++i) {\n\t\tif (!safeIsPrint(string[i])) { // NOLINT\n\t\t\tstring[i] = '.';           // NOLINT\n\t\t}\n\t}\n\treturn std::string{ string, sizeof(in4CC) };\n}\n\nusing Unexpected = std::unexpected<OSStatus>;\n\ntemplate <typename T>\nusing Expected = std::expected<T, OSStatus>;\n\n// expected<reference_wrapper<T>> is unweildy.\n// Instead, extend expected<T*> (with a guarantee that the pointer is non-null).\ntemplate <typename T>\nclass [[nodiscard]] ExpectedPtr : public std::expected<T*, OSStatus> {\npublic:\n\tusing Base = std::expected<T*, OSStatus>;\n\n\t// Caution: default-constructed to null ptr.\n\tExpectedPtr() = default;\n\n\t// Construct with a reference, to enforce non-null guarantee (unless default-constructed).\n\tExpectedPtr(T& ref) : Base{ &ref } {} // NOLINT implicit OK\n\n\tExpectedPtr(Unexpected&& u) : Base{ u } {} // NOLINT implicit OK\n\n\t// unchecked (parallel to expected::operator*); use operator bool to verify\n\tT* operator->() const { return Base::operator*(); }\n\tT* get() const { return Base::operator*(); }\n\tT& operator*() const { return *get(); }\n};\n\ntemplate <typename T>\ninline void ThrowExceptionIfUnexpected(const Expected<T>& e)\n{\n\tif (!e) [[unlikely]] {\n\t\tThrow(e.error());\n\t}\n}\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_AUUtility_h\n"
  },
  {
    "path": "include/AudioUnitSDK/AudioUnitSDK.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AudioUnitSDK.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_h\n#define AudioUnitSDK_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUEffectBase.h>\n#include <AudioUnitSDK/AUInputElement.h>\n#if AUSDK_HAVE_MIDI\n#include <AudioUnitSDK/AUMIDIBase.h>\n#include <AudioUnitSDK/AUMIDIEffectBase.h>\n#endif // AUSDK_HAVE_MIDI\n#include <AudioUnitSDK/AUOutputElement.h>\n#include <AudioUnitSDK/AUPlugInDispatch.h>\n#include <AudioUnitSDK/AUScopeElement.h>\n#include <AudioUnitSDK/AUSilentTimeout.h>\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/ComponentBase.h>\n#if AUSDK_HAVE_MUSIC_DEVICE\n#include <AudioUnitSDK/MusicDeviceBase.h>\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n\n#endif /* AudioUnitSDK_h */\n"
  },
  {
    "path": "include/AudioUnitSDK/ComponentBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/ComponentBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_ComponentBase_h\n#define AudioUnitSDK_ComponentBase_h\n\n// module\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUUtility.h>\n\n// OS\n#include <AudioToolbox/AudioComponent.h>\n\n// std\n#include <array>\n#include <mutex>\n#include <new>\n\nnamespace ausdk {\n\n/*!\n\t@class\tComponentBase\n\t@brief\tBase class for implementing an `AudioComponentInstance`.\n*/\nclass ComponentBase {\npublic:\n\t/// Construct given an AudioComponentInstance, typically from APFactory::Constuct.\n\texplicit ComponentBase(AudioComponentInstance inInstance);\n\n\tvirtual ~ComponentBase() = default;\n\n\tComponentBase(const ComponentBase&) = delete;\n\tComponentBase(ComponentBase&&) = delete;\n\tComponentBase& operator=(const ComponentBase&) = delete;\n\tComponentBase& operator=(ComponentBase&&) = delete;\n\n\t/// Called from dispatchers after constructing an instance.\n\tvoid DoPostConstructor();\n\n\t/// Called from dispatchers before destroying an instance.\n\tvoid DoPreDestructor();\n\n\t/// Obtain the wrapped `AudioComponentInstance` (underlying type of `AudioUnit`, `AudioCodec`,\n\t/// and others).\n\t[[nodiscard]] AudioComponentInstance GetComponentInstance() const noexcept\n\t{\n\t\treturn mComponentInstance;\n\t}\n\n\t/// Return the instance's `AudioComponentDescription`.\n\t[[nodiscard]] AudioComponentDescription GetComponentDescription() const;\n\n\t/// Component dispatch method.\n\tstatic OSStatus AP_Open(void* self, AudioComponentInstance compInstance);\n\n\t/// Component dispatch method.\n\tstatic OSStatus AP_Close(void* self);\n\n\t/// A mutex which is held during `Open`, since some AU's and the Component Manager itself\n\t/// are not thread-safe against globals.\n\tstatic std::recursive_mutex& InitializationMutex();\n\nprotected:\n\t// subclasses are free to to override these methods to add functionality\n\tvirtual void PostConstructor() {}\n\tvirtual void PreDestructor() {}\n\t// these methods, however, are reserved for override only within this SDK\n\tvirtual void PostConstructorInternal() {}\n\tvirtual void PreDestructorInternal() {}\n\nprivate:\n\tAudioComponentInstance mComponentInstance;\n};\n\n/*!\n\t@class\tAudioComponentPlugInInstance\n\t@brief\tObject which implements an AudioComponentPlugInInterface for the framework, and\n\t\t\twhich holds the C++ implementation object.\n*/\nstruct AudioComponentPlugInInstance {\n\t// The AudioComponentPlugInInterface must remain first\n\tAudioComponentPlugInInterface mPlugInInterface{};\n\n\tvoid* (*mConstruct)(void* memory, AudioComponentInstance ci){ nullptr };\n\n\tvoid (*mDestruct)(void* memory){ nullptr };\n\n\tstd::array<void*, 2> mPad{}; // pad to a 16-byte boundary (in either 32 or 64 bit mode)\n\t// the ACI implementation object is constructed into this memory\n\t// (this member is just a placeholder. it is aligned to a 16-byte boundary)\n\tUInt32 mInstanceStorage{ 0 };\n};\n\n/*!\n\t@class\tAPFactory\n\t@tparam\tAPMethodLookup\tA class (e.g. AUBaseLookup) which provides a method selector lookup\n\t\t\t\t\t\t\tfunction.\n\t@tparam\tImplementor\t\tThe class which implements the full plug-in (AudioUnit) interface.\n\t@brief\tProvides an AudioComponentFactoryFunction and a convenience wrapper for\n\t\t\tAudioComponentRegister.\n*/\ntemplate <class APMethodLookup, class Implementor>\nclass APFactory {\npublic:\n\tstatic void* Construct(void* memory, AudioComponentInstance compInstance)\n\t{\n\t\treturn new (memory) Implementor(compInstance); // NOLINT manual memory management\n\t}\n\n\tstatic void Destruct(void* memory) { static_cast<Implementor*>(memory)->~Implementor(); }\n\n\t// This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance.\n\t// The actual implementation object is not created until Open().\n\tstatic AudioComponentPlugInInterface* Factory(const AudioComponentDescription* /* inDesc */)\n\t{\n\t\tauto* const acpi =                                     // NOLINT owning memory\n\t\t\tstatic_cast<AudioComponentPlugInInstance*>(malloc( // NOLINT manual memory management\n\t\t\t\toffsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor)));\n\t\tacpi->mPlugInInterface.Open = ComponentBase::AP_Open;\n\t\tacpi->mPlugInInterface.Close = ComponentBase::AP_Close;\n\t\tacpi->mPlugInInterface.Lookup = APMethodLookup::Lookup;\n\t\tacpi->mPlugInInterface.reserved = nullptr;\n\t\tacpi->mConstruct = Construct;\n\t\tacpi->mDestruct = Destruct;\n\t\tacpi->mPad.fill(nullptr);\n\t\treturn &acpi->mPlugInInterface;\n\t}\n\n\t// This is for runtime registration (not for plug-ins loaded from bundles).\n\tstatic AudioComponent Register(\n\t\tUInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags = 0)\n\t{\n\t\tconst AudioComponentDescription desc = { type, subtype, manuf, flags, 0 };\n\t\treturn AudioComponentRegister(&desc, name, vers, Factory);\n\t}\n};\n\n#ifndef AUSDK_EXPORT\n#if __GNUC__\n#define AUSDK_EXPORT __attribute__((visibility(\"default\"))) // NOLINT\n#else\n#warning export?\n#endif\n#endif\n\n\n/// Macro to generate the factory function for the specified Audio Component. Factory is an\n/// APFactory such as AUBaseFactory. Class is the name of the final ComponentBase class which\n/// implements instances of the class.\n#define AUSDK_COMPONENT_ENTRY(FactoryType, Class) /* NOLINT macro */                               \\\n\tAUSDK_EXPORT                                                                                   \\\n\textern \"C\" void* Class##Factory(const AudioComponentDescription* inDesc);                      \\\n\textern \"C\" void* Class##Factory(const AudioComponentDescription* inDesc)                       \\\n\t{                                                                                              \\\n\t\treturn FactoryType<Class>::Factory(inDesc); /* NOLINT parens */                            \\\n\t}\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_ComponentBase_h\n"
  },
  {
    "path": "include/AudioUnitSDK/MusicDeviceBase.h",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/MusicDeviceBase.h\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#ifndef AudioUnitSDK_MusicDeviceBase_h\n#define AudioUnitSDK_MusicDeviceBase_h\n\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUMIDIBase.h>\n\n#include <AudioToolbox/MusicDevice.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n// ________________________________________________________________________\n//\tMusicDeviceBase\n//\n\n/*!\n\t@class\tMusicDeviceBase\n\t@brief\tDeriving from AUBase and AUMIDIBase, an abstract base class for Music Device\n\t\t\tsubclasses.\n*/\nclass MusicDeviceBase : public AUBase, public AUMIDIBase {\npublic:\n\tMusicDeviceBase(AudioComponentInstance inInstance, UInt32 numInputs, UInt32 numOutputs,\n\t\tUInt32 numGroups = 0);\n\n\tOSStatus MIDIEvent(\n\t\tUInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) override\n\t{\n\t\treturn AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);\n\t}\n\tOSStatus SysEx(const UInt8* inData, UInt32 inLength) override\n\t{\n\t\treturn AUMIDIBase::SysEx(inData, inLength);\n\t}\n\n#if AUSDK_HAVE_MIDI2\n\tOSStatus MIDIEventList(\n\t\tUInt32 inOffsetSampleFrame, const struct MIDIEventList* eventList) override\n\t{\n\t\treturn AUMIDIBase::MIDIEventList(inOffsetSampleFrame, eventList);\n\t}\n#endif\n\n\tOSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override;\n\tOSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, void* outData) override;\n\tOSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\t\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize) override;\n\tOSStatus HandleNoteOn(\n\t\tUInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) override;\n\tOSStatus HandleNoteOff(\n\t\tUInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) override;\n\tvirtual OSStatus GetInstrumentCount(UInt32& outInstCount) const;\n};\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AudioUnitSDK_MusicDeviceBase_h\n"
  },
  {
    "path": "readme.md",
    "content": "# AudioUnitSDK\n\n## Overview\nThe AudioUnitSDK contains a set of base classes as well as utility sources required for Audio Unit development. These utility classes extend or wrap Core Audio API’s providing developers with the essential scaffolding to create audio effects, instruments, and generators on Apple platforms. They provide an easier to implement C++ class model wrapping the C framework APIs.\n\n## Installing dependencies\n1. Install [Xcode][Xcode]\n\n[Xcode]: https://developer.apple.com/xcode/resources/\n\n## Building the project\n1. Open AudioUnitSDK.xcodeproj\n2. Build the AudioUnitSDK target\n3. Add the `include` folder to your projects Header Search Paths\n4. Link libAudioUnitSDK.a to your project\n\n\nAlternatively, you can add the AudioUnitSDK source directly to your project and build as part of your target. \n\n## Supported Deployment Targets\nmacOS 11.0 / iOS 14.0 or later.\n\n## Changelog\n\n### Version 1.4.0\n\n##### Additions\n\n- Adopted `[[clang::nonblocking]]` attribute throughout the SDK using `AUSDK_RTSAFE_TYPE` and `AUSDK_RTSAFE_SECTION` macros with support for \"loose\" real-time safety contract.\n\n##### Changes\n\n- C++ language version to `C++23` for `std::expected`.\n- Improved exception safety throughout render paths and buffer allocations.\n- Minor bug fixes.\n\n##### Security\n\n- Fixed out-of-bounds read in AUMIDIBase deserialization.\n\n### Version 1.3.0\n\n- Minor updates and bug fixes.\n\n### Version 1.2.0\n\n##### Additions\n\n- New header `AUConfig.h` for improved project organization.\n\n##### Changes\n\n- C++ language version to `C++20` for modern language features.\n\n### Version 1.1.0\n\n##### Changes\n\n- The `Source` folder was split in two folders: `include` for public headers, and `src` for private source files.\nUsers building the AudioUnitSDK sources from within their Xcode project should update the source file locations and change the include path to `path/to/AudioUnitSDK/include`. \nInclude directives should be prefixed with AudioUnitSDK (i.e. `#include \"AudioUnitSDK/AUBase.h\"` instead of `#include \"AUBase.h\"`).\n\n### Version 1.0.0\n\n- Initial upload.\n\nCopyright (C) 2023 Apple Inc. All rights reserved.\n"
  },
  {
    "path": "src/AudioUnitSDK/AUBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUInputElement.h>\n#include <AudioUnitSDK/AUOutputElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <algorithm>\n#include <array>\n#include <atomic>\n#include <cassert>\n#include <cstddef>\n#include <cstring>\n#include <limits>\n#include <span>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n#if TARGET_OS_MAC && (TARGET_CPU_X86 || TARGET_CPU_X86_64)\n\nclass DenormalDisabler {\npublic:\n\tDenormalDisabler() noexcept : mSavedMXCSR(GetCSR()) { SetCSR(mSavedMXCSR | 0x8040); }\n\n\tDenormalDisabler(const DenormalDisabler&) = delete;\n\tDenormalDisabler(DenormalDisabler&&) = delete;\n\tDenormalDisabler& operator=(const DenormalDisabler&) = delete;\n\tDenormalDisabler& operator=(DenormalDisabler&&) = delete;\n\n\t~DenormalDisabler() noexcept { SetCSR(mSavedMXCSR); }\n\nprivate:\n#if 0 // not sure if this is right: // #if __has_include(<xmmintrin.h>)\n\tstatic unsigned GetCSR() noexcept { return _mm_getcsr(); }\n\tstatic void SetCSR(unsigned x) noexcept { _mm_setcsr(x); }\n#else\n\t// our compiler does ALL floating point with SSE\n\tstatic unsigned GetCSR() noexcept\n\t{\n\t\tunsigned result{};\n\t\tasm volatile(\"stmxcsr %0\" : \"=m\"(*&result)); // NOLINT asm\n\t\treturn result;\n\t}\n\tstatic void SetCSR(unsigned a) noexcept\n\t{\n\t\tunsigned temp = a;\n\t\tasm volatile(\"ldmxcsr %0\" : : \"m\"(*&temp)); // NOLINT asm\n\t}\n#endif\n\n\tconst unsigned mSavedMXCSR;\n};\n\n#else\n// while denormals can be flushed to zero on ARM processors, there is no performance benefit\nclass DenormalDisabler {\npublic:\n\tDenormalDisabler() = default;\n};\n#endif\n\nstatic CFStringRef GetPresetDefaultName() noexcept\n{\n\tstatic const auto name = CFSTR(\"Untitled\");\n\treturn name;\n}\n\nstatic constexpr auto kNoLastRenderedSampleTime = std::numeric_limits<Float64>::lowest();\n\n//_____________________________________________________________________________\n//\nAUBase::AUBase(AudioComponentInstance inInstance, UInt32 numInputElements, UInt32 numOutputElements,\n\tUInt32 numGroupElements)\n\t: ComponentBase(inInstance), mInitNumInputEls(numInputElements),\n\t  mInitNumOutputEls(numOutputElements), mInitNumGroupEls(numGroupElements),\n\t  mLogString(CreateLoggingString())\n{\n\tResetRenderTime();\n\n\tGlobalScope().Initialize(this, kAudioUnitScope_Global, 1);\n\n\tmCurrentPreset.presetNumber = -1;\n\tCFRetain(mCurrentPreset.presetName = GetPresetDefaultName());\n}\n\n//_____________________________________________________________________________\n//\nAUBase::~AUBase()\n{\n\tif (mCurrentPreset.presetName != nullptr) {\n\t\tCFRelease(mCurrentPreset.presetName);\n\t}\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::PostConstructorInternal()\n{\n\t// invoked after construction because they are virtual methods and/or call virtual methods\n\tif (mMaxFramesPerSlice == 0) {\n\t\tSetMaxFramesPerSlice(kAUDefaultMaxFramesPerSlice);\n\t}\n\tCreateElements();\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::PreDestructorInternal()\n{\n\t// this is called from the ComponentBase dispatcher, which doesn't know anything about our\n\t// (optional) lock\n\tconst AUEntryGuard guard(mAUMutex);\n\tDoCleanup();\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::CreateElements()\n{\n\tif (!mElementsCreated) {\n\t\tInputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls);\n\t\tOutputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls);\n\t\tGroups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls);\n\t\tCreateExtendedElements();\n\n\t\tmElementsCreated = true;\n\t}\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::SetMaxFramesPerSlice(UInt32 nFrames)\n{\n\tif (nFrames == mMaxFramesPerSlice) {\n\t\treturn;\n\t}\n\n\tmMaxFramesPerSlice = nFrames;\n\tif (mBuffersAllocated) {\n\t\tReallocateBuffers();\n\t}\n\tPropertyChanged(kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0);\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::CanSetMaxFrames() const\n{\n\treturn IsInitialized() ? kAudioUnitErr_Initialized : OSStatus(noErr);\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::ReallocateBuffers()\n{\n\tCreateElements();\n\n\tconst UInt32 nOutputs = Outputs().GetNumberOfElements();\n\tfor (UInt32 i = 0; i < nOutputs; ++i) {\n\t\tOutput(i).AllocateBuffer(); // does no work if already allocated\n\t}\n\tconst UInt32 nInputs = Inputs().GetNumberOfElements();\n\tfor (UInt32 i = 0; i < nInputs; ++i) {\n\t\tInput(i).AllocateBuffer(); // does no work if already allocated\n\t}\n\tmBuffersAllocated = true;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::DeallocateIOBuffers()\n{\n\tif (!mBuffersAllocated) {\n\t\treturn;\n\t}\n\n\tconst UInt32 nOutputs = Outputs().GetNumberOfElements();\n\tfor (UInt32 i = 0; i < nOutputs; ++i) {\n\t\tOutput(i).DeallocateBuffer();\n\t}\n\tconst UInt32 nInputs = Inputs().GetNumberOfElements();\n\tfor (UInt32 i = 0; i < nInputs; ++i) {\n\t\tInput(i).DeallocateBuffer();\n\t}\n\tmBuffersAllocated = false;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DoInitialize()\n{\n\tif (!mInitialized) {\n\t\tAUSDK_Require_noerr(Initialize());\n\t\tif (CanScheduleParameters()) {\n\t\t\tmParamEventList.reserve(24); // NOLINT magic #\n\t\t}\n\t\tmHasBegunInitializing = true;\n\t\tReallocateBuffers(); // calls CreateElements()\n\t\tmInitialized = true; // signal that it's okay to render\n\t\tstd::atomic_thread_fence(std::memory_order_seq_cst);\n\t}\n\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::Initialize() { return noErr; }\n\n//_____________________________________________________________________________\n//\nvoid AUBase::DoCleanup()\n{\n\tif (mInitialized) {\n\t\tCleanup();\n\t}\n\n\tDeallocateIOBuffers();\n\tResetRenderTime();\n\n\tmInitialized = false;\n\tmHasBegunInitializing = false;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::Cleanup() {}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DoReset(AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\tResetRenderTime();\n\treturn Reset(inScope, inElement);\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::Reset(AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\treturn BaseReset(inScope, inElement);\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DispatchGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable)\n{\n\tOSStatus result = noErr;\n\tbool validateElement = true;\n\n\tswitch (inID) {\n\tcase kAudioUnitProperty_MakeConnection:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global,\n\t\t\tkAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(AudioUnitConnection);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_SetRenderCallback:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global,\n\t\t\tkAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(AURenderCallbackStruct);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_StreamFormat:\n\t\toutDataSize = sizeof(AudioStreamBasicDescription);\n\t\toutWritable = IsStreamFormatWritable(inScope, inElement);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_SampleRate:\n\t\toutDataSize = sizeof(Float64);\n\t\toutWritable = IsStreamFormatWritable(inScope, inElement);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ClassInfo:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(CFPropertyListRef);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_FactoryPresets:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require_noerr(GetPresets(nullptr));\n\t\toutDataSize = sizeof(CFArrayRef);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_PresentPreset:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(AUPreset);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ElementName:\n\t\toutDataSize = sizeof(CFStringRef);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ParameterList: {\n\t\tUInt32 nParams = 0;\n\t\tAUSDK_Require_noerr(GetParameterList(inScope, nullptr, nParams));\n\t\toutDataSize = sizeof(AudioUnitParameterID) * nParams;\n\t\toutWritable = false;\n\t\tvalidateElement = false;\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ParameterInfo:\n\t\toutDataSize = sizeof(AudioUnitParameterInfo);\n\t\toutWritable = false;\n\t\tvalidateElement = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ParameterHistoryInfo:\n\t\toutDataSize = sizeof(AudioUnitParameterHistoryInfo);\n\t\toutWritable = false;\n\t\tvalidateElement = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ElementCount:\n\t\toutDataSize = sizeof(UInt32);\n\t\toutWritable = BusCountWritable(inScope);\n\t\tvalidateElement = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_Latency:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(Float64);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_TailTime:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(SupportsTail(), kAudioUnitErr_InvalidProperty);\n\t\toutDataSize = sizeof(Float64);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_MaximumFramesPerSlice:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(UInt32);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_LastRenderError:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(OSStatus);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_SupportedNumChannels: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tconst UInt32 num = SupportedNumChannels(nullptr);\n\t\tAUSDK_Require(num != 0u, kAudioUnitErr_InvalidProperty);\n\t\toutDataSize = sizeof(AUChannelInfo) * num;\n\t\toutWritable = false;\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_SupportedChannelLayoutTags: {\n\t\tconst auto tags = GetChannelLayoutTags(inScope, inElement);\n\t\tAUSDK_Require(!tags.empty(), kAudioUnitErr_InvalidProperty);\n\t\toutDataSize = static_cast<UInt32>(std::span(tags).size_bytes());\n\t\toutWritable = false;\n\t\tvalidateElement = false; // already done it\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_AudioChannelLayout: {\n\t\toutWritable = false;\n\t\toutDataSize = GetAudioChannelLayout(inScope, inElement, nullptr, outWritable);\n\t\tif (outDataSize != 0u) {\n\t\t\tresult = noErr;\n\t\t} else {\n\t\t\tconst auto tags = GetChannelLayoutTags(inScope, inElement);\n\t\t\treturn tags.empty() ? kAudioUnitErr_InvalidProperty\n\t\t\t\t\t\t\t\t: kAudioUnitErr_InvalidPropertyValue;\n\t\t}\n\t\tvalidateElement = false; // already done it\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ShouldAllocateBuffer:\n\t\tAUSDK_Require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output),\n\t\t\tkAudioUnitErr_InvalidScope);\n\t\toutWritable = true;\n\t\toutDataSize = sizeof(UInt32);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ParameterValueStrings:\n\t\tAUSDK_Require_noerr(GetParameterValueStrings(inScope, inElement, nullptr));\n\t\toutDataSize = sizeof(CFArrayRef);\n\t\toutWritable = false;\n\t\tvalidateElement = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_HostCallbacks:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(mHostCallbackInfo);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ContextName:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(CFStringRef);\n\t\toutWritable = true;\n\t\tbreak;\n\n\n#if AUSDK_HAVE_UI && !TARGET_OS_IPHONE\n\tcase kAudioUnitProperty_IconLocation:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(HasIcon(), kAudioUnitErr_InvalidProperty);\n\t\toutWritable = false;\n\t\toutDataSize = sizeof(CFURLRef);\n\t\tbreak;\n#endif\n\n\tcase kAudioUnitProperty_ParameterClumpName:\n\t\toutDataSize = sizeof(AudioUnitParameterNameInfo);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_LastRenderSampleTime:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(Float64);\n\t\toutWritable = false;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_NickName:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(CFStringRef);\n\t\toutWritable = true;\n\t\tbreak;\n\n\tdefault:\n\t\tresult = GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);\n\t\tvalidateElement = false;\n\t\tbreak;\n\t}\n\n\tif ((result == noErr) && validateElement) {\n\t\tAUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);\n\t}\n\n\treturn result;\n}\n\n//_____________________________________________________________________________\n//\n// NOLINTNEXTLINE(misc-no-recursion) with SaveState\nOSStatus AUBase::DispatchGetProperty(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)\n{\n\t// NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which\n\t// calls DispatchGetPropertyInfo first, which performs validation of the scope/element,\n\t// and ensures that the outData buffer is non-null and large enough.\n\tOSStatus result = noErr;\n\n\tswitch (inID) {\n\tcase kAudioUnitProperty_StreamFormat:\n\t\tSerialize(GetStreamFormat(inScope, inElement), outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_SampleRate:\n\t\tSerialize(GetStreamFormat(inScope, inElement).mSampleRate, outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ParameterList: {\n\t\tUInt32 parameterCount = 0;\n\t\tresult = GetParameterList(inScope, nullptr, parameterCount);\n\t\tif (result == noErr) {\n\t\t\tstd::vector<AudioUnitParameterID> parameterIDs(parameterCount);\n\t\t\tresult = GetParameterList(inScope, parameterIDs.data(), parameterCount);\n\t\t\tif (result == noErr) {\n\t\t\t\tSerialize(std::span(parameterIDs), outData);\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ParameterInfo: {\n\t\tAudioUnitParameterInfo parameterInfo{};\n\t\tresult = GetParameterInfo(inScope, inElement, parameterInfo);\n\t\tSerialize(parameterInfo, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ParameterHistoryInfo: {\n\t\tAudioUnitParameterHistoryInfo info{};\n\t\tresult = GetParameterHistoryInfo(\n\t\t\tinScope, inElement, info.updatesPerSecond, info.historyDurationInSeconds);\n\t\tSerialize(info, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ClassInfo: {\n\t\tCFPropertyListRef plist = nullptr;\n\t\tresult = SaveState(&plist);\n\t\tSerialize(plist, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_FactoryPresets: {\n\t\tCFArrayRef array = nullptr;\n\t\tresult = GetPresets(&array);\n\t\tSerialize(array, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_PresentPreset: {\n\t\tSerialize(mCurrentPreset, outData);\n\n\t\t// retain current string (as client owns a reference to it and will release it)\n\t\tif ((inID == kAudioUnitProperty_PresentPreset) && (mCurrentPreset.presetName != nullptr)) {\n\t\t\tCFRetain(mCurrentPreset.presetName);\n\t\t}\n\n\t\tresult = noErr;\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ElementName: {\n\t\tconst AUElement* const element = GetElement(inScope, inElement);\n\t\tconst CFStringRef name = *element->GetName();\n\t\tAUSDK_Require(name != nullptr, kAudioUnitErr_PropertyNotInUse);\n\t\tCFRetain(name); // must return a +1 reference\n\t\tSerialize(name, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ElementCount:\n\t\tSerialize(GetScope(inScope).GetNumberOfElements(), outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_Latency:\n\t\tSerialize(GetLatency(), outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_TailTime:\n\t\tAUSDK_Require(SupportsTail(), kAudioUnitErr_InvalidProperty);\n\t\tSerialize(GetTailTime(), outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_MaximumFramesPerSlice:\n\t\tSerialize(mMaxFramesPerSlice, outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_LastRenderError:\n\t\tSerialize(mLastRenderError, outData);\n\t\tmLastRenderError = 0;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_SupportedNumChannels: {\n\t\tconst AUChannelInfo* infos = nullptr;\n\t\tconst auto count = SupportedNumChannels(&infos);\n\t\tif ((count > 0) && (infos != nullptr)) {\n\t\t\tSerialize(std::span(infos, count), outData);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_SupportedChannelLayoutTags: {\n\t\tconst auto tags = GetChannelLayoutTags(inScope, inElement);\n\t\tAUSDK_Require(!tags.empty(), kAudioUnitErr_InvalidProperty);\n\t\tSerialize(std::span(tags), outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_AudioChannelLayout: {\n\t\tauto* const acl = static_cast<AudioChannelLayout*>(outData);\n\t\tbool writable = false;\n\t\tconst auto dataSize = GetAudioChannelLayout(inScope, inElement, acl, writable);\n\t\tAUSDK_Require(dataSize != 0, kAudioUnitErr_InvalidProperty);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ShouldAllocateBuffer: {\n\t\tconst auto& element = IOElement(inScope, inElement);\n\t\tSerialize(static_cast<UInt32>(element.WillAllocateBuffer()), outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ParameterValueStrings: {\n\t\tCFArrayRef array = nullptr;\n\t\tresult = GetParameterValueStrings(inScope, inElement, &array);\n\t\tSerialize(array, outData);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_HostCallbacks:\n\t\tSerialize(mHostCallbackInfo, outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_ContextName: {\n\t\tconst auto* const name = *mContextName;\n\t\tSerialize(name, outData);\n\t\tif (name) {\n\t\t\tCFRetain(name); // must return a +1 reference\n\t\t\tresult = noErr;\n\t\t} else {\n\t\t\tresult = kAudioUnitErr_PropertyNotInUse;\n\t\t}\n\t\tbreak;\n\t}\n\n#if AUSDK_HAVE_UI && !TARGET_OS_IPHONE\n\tcase kAudioUnitProperty_IconLocation: {\n\t\tconst auto iconLocation = CopyIconLocation();\n\t\tAUSDK_Require(iconLocation != nullptr, kAudioUnitErr_InvalidProperty);\n\t\tSerialize(iconLocation, outData);\n\t\tbreak;\n\t}\n#endif\n\n\tcase kAudioUnitProperty_ParameterClumpName: {\n\t\tauto clumpInfo = Deserialize<AudioUnitParameterNameInfo>(outData);\n\t\tAUSDK_Require(clumpInfo.inID != kAudioUnitClumpID_System,\n\t\t\tkAudioUnitErr_InvalidPropertyValue); // this ID value is reserved\n\t\tresult = CopyClumpName(inScope, clumpInfo.inID,\n\t\t\tstatic_cast<UInt32>(std::max(clumpInfo.inDesiredLength, SInt32(0))),\n\t\t\t&clumpInfo.outName);\n\t\tSerialize(clumpInfo, outData);\n\n\t\t// this is provided for compatbility with existing implementations that don't know\n\t\t// about this new mechanism\n\t\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\t\tresult = GetProperty(inID, inScope, inElement, outData);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_LastRenderSampleTime:\n\t\tSerialize(mCurrentRenderTime.mSampleTime, outData);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_NickName: {\n\t\tconst auto* const name = *mNickName;\n\t\tSerialize(name, outData);\n\t\t// Ownership follows Core Foundation's 'Copy Rule'\n\t\tif (name) {\n\t\t\tCFRetain(name);\n\t\t}\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tresult = GetProperty(inID, inScope, inElement, outData);\n\t\tbreak;\n\t}\n\treturn result;\n}\n\n\n//_____________________________________________________________________________\n//\n// Note: We can be sure inData is non-null; otherwise RemoveProperty would have been called.\n// NOLINTNEXTLINE(misc-no-recursion) with RestoreState\nOSStatus AUBase::DispatchSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n{\n\tOSStatus result = noErr;\n\n\tswitch (inID) {\n\tcase kAudioUnitProperty_MakeConnection: {\n\t\tAUSDK_Require(\n\t\t\tinDataSize >= sizeof(AudioUnitConnection), kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto connection = Deserialize<AudioUnitConnection>(inData);\n\t\tresult = SetConnection(connection);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_SetRenderCallback: {\n\t\tAUSDK_Require(\n\t\t\tinDataSize >= sizeof(AURenderCallbackStruct), kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto callback = Deserialize<AURenderCallbackStruct>(inData);\n\t\tresult = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement,\n\t\t\tcallback.inputProc, callback.inputProcRefCon);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ElementCount:\n\t\tAUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(BusCountWritable(inScope), kAudioUnitErr_PropertyNotWritable);\n\t\tresult = SetBusCount(inScope, Deserialize<UInt32>(inData));\n\t\tif (result == noErr) {\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\t\tbreak;\n\n\tcase kAudioUnitProperty_MaximumFramesPerSlice:\n\t\tAUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require_noerr(CanSetMaxFrames());\n\t\tSetMaxFramesPerSlice(Deserialize<UInt32>(inData));\n\t\tbreak;\n\n\tcase kAudioUnitProperty_StreamFormat: {\n\t\tconstexpr static UInt32 kMinimumValidASBDSize = 36;\n\t\tAUSDK_Require(inDataSize >= kMinimumValidASBDSize, kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);\n\n\t\tAudioStreamBasicDescription newDesc{};\n\t\t// now we're going to be ultra conservative! because of discrepancies between\n\t\t// sizes of this struct based on aligment padding inconsistencies\n\t\tmemcpy(&newDesc, inData, kMinimumValidASBDSize);\n\n\t\tAUSDK_Require(ASBD::MinimalSafetyCheck(newDesc), kAudioUnitErr_FormatNotSupported);\n\n\t\tAUSDK_Require(ValidFormat(inScope, inElement, newDesc), kAudioUnitErr_FormatNotSupported);\n\n\t\tconst auto curDesc = GetStreamFormat(inScope, inElement);\n\n\t\tif (!ASBD::IsEqual(curDesc, newDesc)) {\n\t\t\tAUSDK_Require(\n\t\t\t\tIsStreamFormatWritable(inScope, inElement), kAudioUnitErr_PropertyNotWritable);\n\t\t\tresult = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_SampleRate: {\n\t\tAUSDK_Require(inDataSize == sizeof(Float64), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);\n\n\t\tconst auto curDesc = GetStreamFormat(inScope, inElement);\n\t\tAudioStreamBasicDescription newDesc = curDesc;\n\t\tnewDesc.mSampleRate = Deserialize<Float64>(inData);\n\n\t\tAUSDK_Require(ValidFormat(inScope, inElement, newDesc), kAudioUnitErr_FormatNotSupported);\n\n\t\tif (!ASBD::IsEqual(curDesc, newDesc)) {\n\t\t\tAUSDK_Require(\n\t\t\t\tIsStreamFormatWritable(inScope, inElement), kAudioUnitErr_PropertyNotWritable);\n\t\t\tresult = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_AudioChannelLayout: {\n\t\t// Check the variable-size AudioChannelLayout object size:\n\t\t// - Is the memory area big enough so that AudioChannelLayout::mNumberChannelDescriptions\n\t\t// can be read?\n\t\tAUSDK_Require(\n\t\t\tinDataSize >= AUChannelLayout::DataByteSize(0), kAudioUnitErr_InvalidPropertyValue);\n\t\t// - Is the whole size consistent?\n\t\tusing NumberChannelDescriptionsT = decltype(AudioChannelLayout::mNumberChannelDescriptions);\n\t\tconstexpr auto numberChannelDescriptionsOffset =\n\t\t\toffsetof(AudioChannelLayout, mNumberChannelDescriptions);\n\t\tconst auto numberChannelDescriptions = Deserialize<NumberChannelDescriptionsT>(\n\t\t\tstatic_cast<const std::byte*>(inData) + numberChannelDescriptionsOffset);\n\t\tAUSDK_Require(inDataSize >= AUChannelLayout::DataByteSize(numberChannelDescriptions),\n\t\t\tkAudioUnitErr_InvalidPropertyValue);\n\n\t\t// copy incoming data to storage aligned for the object type\n\t\tconst size_t padding = ((inDataSize % sizeof(AudioChannelLayout)) > 0) ? 1 : 0;\n\t\tstd::vector<AudioChannelLayout> layout((inDataSize / sizeof(AudioChannelLayout)) + padding);\n\t\tstd::memcpy(layout.data(), inData, inDataSize);\n\n\t\tresult = SetAudioChannelLayout(inScope, inElement, layout.data());\n\t\tif (result == noErr) {\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ClassInfo:\n\t\tAUSDK_Require(inDataSize == sizeof(CFPropertyListRef), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tresult = RestoreState(Deserialize<CFPropertyListRef>(inData));\n\t\tbreak;\n\n\tcase kAudioUnitProperty_PresentPreset: {\n\t\tAUSDK_Require(inDataSize == sizeof(AUPreset), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tconst auto newPreset = Deserialize<AUPreset>(inData);\n\n\t\tif (newPreset.presetNumber >= 0) {\n\t\t\tresult = NewFactoryPresetSet(newPreset);\n\t\t\t// NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid\n\t\t\t// from its own list of preset number->name\n\t\t\tif (result == noErr) {\n\t\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t\t}\n\t\t} else if (newPreset.presetName != nullptr) {\n\t\t\tresult = NewCustomPresetSet(newPreset);\n\t\t\tif (result == noErr) {\n\t\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t\t}\n\t\t} else {\n\t\t\tresult = kAudioUnitErr_InvalidPropertyValue;\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ElementName: {\n\t\tAUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);\n\t\tAUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto element = GetScope(inScope).GetElement(inElement);\n\t\telement->SetName(Deserialize<CFStringRef>(inData));\n\t\tPropertyChanged(inID, inScope, inElement);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ShouldAllocateBuffer: {\n\t\tAUSDK_Require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output),\n\t\t\tkAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);\n\t\tAUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(!IsInitialized(), kAudioUnitErr_Initialized);\n\n\t\tauto& element = IOElement(inScope, inElement);\n\t\telement.SetWillAllocateBuffer(Deserialize<UInt32>(inData) != 0);\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_HostCallbacks: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tconst auto availSize = std::min(static_cast<size_t>(inDataSize), sizeof(HostCallbackInfo));\n\t\tconst bool hasChanged = memcmp(&mHostCallbackInfo, inData, availSize) != 0;\n\t\tmHostCallbackInfo = {};\n\t\tmemcpy(&mHostCallbackInfo, inData, availSize);\n\t\tif (hasChanged) {\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ContextName:\n\t\tAUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tmContextName = Deserialize<CFStringRef>(inData);\n\t\tPropertyChanged(inID, inScope, inElement);\n\t\tbreak;\n\n\tcase kAudioUnitProperty_NickName:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);\n\t\tmNickName = Deserialize<CFStringRef>(inData);\n\t\tPropertyChanged(inID, inScope, inElement);\n\t\tbreak;\n\n\tdefault:\n\t\tresult = SetProperty(inID, inScope, inElement, inData, inDataSize);\n\t\tif (result == noErr) {\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\n\t\tbreak;\n\t}\n\treturn result;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DispatchRemovePropertyValue(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\tOSStatus result = noErr;\n\tswitch (inID) {\n\tcase kAudioUnitProperty_AudioChannelLayout: {\n\t\tresult = RemoveAudioChannelLayout(inScope, inElement);\n\t\tif (result == noErr) {\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_HostCallbacks: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tconstexpr decltype(mHostCallbackInfo) zeroInfo{};\n\t\tif (memcmp(&mHostCallbackInfo, &zeroInfo, sizeof(mHostCallbackInfo)) != 0) {\n\t\t\tmHostCallbackInfo = {};\n\t\t\tPropertyChanged(inID, inScope, inElement);\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase kAudioUnitProperty_ContextName:\n\t\tmContextName = nullptr;\n\t\tresult = noErr;\n\t\tbreak;\n\n\tcase kAudioUnitProperty_NickName: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tmNickName = nullptr;\n\t\tPropertyChanged(inID, inScope, inElement);\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tresult = RemovePropertyValue(inID, inScope, inElement);\n\t\tbreak;\n\t}\n\n\treturn result;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetPropertyInfo(AudioUnitPropertyID /*inID*/, AudioUnitScope /*inScope*/,\n\tAudioUnitElement /*inElement*/, UInt32& /*outDataSize*/, bool& /*outWritable*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetProperty(AudioUnitPropertyID /*inID*/, AudioUnitScope /*inScope*/,\n\tAudioUnitElement /*inElement*/, void* /*outData*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::SetProperty(AudioUnitPropertyID /*inID*/, AudioUnitScope /*inScope*/,\n\tAudioUnitElement /*inElement*/, const void* /*inData*/, UInt32 /*inDataSize*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::RemovePropertyValue(\n\tAudioUnitPropertyID /*inID*/, AudioUnitScope /*inScope*/, AudioUnitElement /*inElement*/)\n{\n\treturn kAudioUnitErr_InvalidPropertyValue;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::AddPropertyListener(\n\tAudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcRefCon)\n{\n\tconst PropertyListener pl{\n\t\t.propertyID = inID, .listenerProc = inProc, .listenerRefCon = inProcRefCon\n\t};\n\n\tif (mPropertyListeners.empty()) {\n\t\tmPropertyListeners.reserve(32); // NOLINT magic#\n\t}\n\tmPropertyListeners.push_back(pl);\n\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::RemovePropertyListener(AudioUnitPropertyID inID,\n\tAudioUnitPropertyListenerProc inProc, void* inProcRefCon, bool refConSpecified)\n{\n\tstd::erase_if(mPropertyListeners, [&](auto& item) {\n\t\treturn item.propertyID == inID && item.listenerProc == inProc &&\n\t\t\t   (!refConSpecified || item.listenerRefCon == inProcRefCon);\n\t});\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::PropertyChanged(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\tfor (const auto& pl : mPropertyListeners) {\n\t\tif (pl.propertyID == inID) {\n\t\t\t(pl.listenerProc)(pl.listenerRefCon, GetComponentInstance(), inID, inScope, inElement);\n\t\t}\n\t}\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::SetRenderNotification(AURenderCallback inProc, void* inRefCon)\n{\n\tif (inProc == nullptr) {\n\t\treturn kAudio_ParamError;\n\t}\n\n\tmRenderCallbacksTouched = true;\n\tmRenderCallbacks.Add(RenderCallback(inProc, inRefCon));\n\t// this will do nothing if it's already in the list\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::RemoveRenderNotification(AURenderCallback inProc, void* inRefCon)\n{\n\tmRenderCallbacks.Remove(RenderCallback(inProc, inRefCon));\n\treturn noErr; // error?\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetParameter(AudioUnitParameterID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, AudioUnitParameterValue& outValue) AUSDK_RTSAFE\n{\n\tAUElement& elem = AUSDK_UnwrapOrReturnError(GetElementOrError(inScope, inElement));\n\toutValue = AUSDK_UnwrapOrReturnError(elem.GetParameterOrError(inID));\n\treturn noErr;\n}\n\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::SetParameter(AudioUnitParameterID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, AudioUnitParameterValue inValue,\n\tUInt32 /*inBufferOffsetInFrames*/) AUSDK_RTSAFE\n{\n\tAUElement& elem = AUSDK_UnwrapOrReturnError(GetElementOrError(inScope, inElement));\n\tAUSDK_CheckReturnError(elem.SetParameterOrError(inID, inValue));\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::ScheduleParameter(\n\tconst AudioUnitParameterEvent* inParameterEvent, UInt32 inNumEvents) AUSDK_RTSAFE\n{\n\tconst bool canScheduleParameters = CanScheduleParameters();\n\n\tfor (UInt32 i = 0; i < inNumEvents; ++i) {\n\t\tconst auto& pe = inParameterEvent[i]; // NOLINT subscript\n\t\tif (pe.eventType == kParameterEvent_Immediate) {\n\t\t\tSetParameter(pe.parameter, pe.scope, pe.element,\n\t\t\t\tpe.eventValues.immediate.value,         // NOLINT union\n\t\t\t\tpe.eventValues.immediate.bufferOffset); // NOLINT union\n\t\t}\n\t\tif (canScheduleParameters) {\n\t\t\t// TODO: Need a realtime-safe parameter schedule\n\t\t\tAUSDK_RT_UNSAFE(mParamEventList.push_back(pe));\n\t\t}\n\t}\n\n\treturn noErr;\n}\n\n// ____________________________________________________________________________\n//\nconstexpr bool ParameterEventListSortPredicate(\n\tconst AudioUnitParameterEvent& ev1, const AudioUnitParameterEvent& ev2) AUSDK_RTSAFE\n{\n\tconstexpr auto bufferOffset = [](const AudioUnitParameterEvent& event) {\n\t\t// ramp.startBufferOffset is signed\n\t\treturn (event.eventType == kParameterEvent_Immediate)\n\t\t\t\t   ? static_cast<SInt32>(event.eventValues.immediate.bufferOffset) // NOLINT union\n\t\t\t\t   : event.eventValues.ramp.startBufferOffset;                     // NOLINT union\n\t};\n\n\treturn bufferOffset(ev1) < bufferOffset(ev2);\n}\n\n// ____________________________________________________________________________\n//\nOSStatus AUBase::ProcessForScheduledParams(\n\tParameterEventList& inParamList, UInt32 inFramesToProcess, void* inUserData) AUSDK_RTSAFE\n{\n\tOSStatus result = noErr;\n\n\tUInt32 framesRemaining = inFramesToProcess;\n\n\tUInt32 currentStartFrame = 0; // start of the whole buffer\n\n\n\t// sort the ParameterEventList by startBufferOffset\n\tstd::ranges::sort(inParamList, RTSafeFP{ ParameterEventListSortPredicate });\n\n\twhile (framesRemaining > 0) {\n\t\t// first of all, go through the ramped automation events and find out where the next\n\t\t// division of our whole buffer will be\n\n\t\tUInt32 currentEndFrame = inFramesToProcess; // start out assuming we'll process all the way\n\t\t\t\t\t\t\t\t\t\t\t\t\t// to the end of the buffer\n\n\t\t// find the next break point\n\t\tfor (const auto& event : inParamList) {\n\t\t\tSInt32 offset =\n\t\t\t\tevent.eventType == kParameterEvent_Immediate\n\t\t\t\t\t? static_cast<SInt32>(event.eventValues.immediate.bufferOffset) // NOLINT\n\t\t\t\t\t: event.eventValues.ramp.startBufferOffset;\n\n\t\t\tif (offset > static_cast<SInt32>(currentStartFrame) &&\n\t\t\t\toffset < static_cast<SInt32>(currentEndFrame)) {\n\t\t\t\tcurrentEndFrame = static_cast<UInt32>(offset);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// consider ramp end to be a possible choice (there may be gaps in the supplied ramp\n\t\t\t// events)\n\t\t\tif (event.eventType == kParameterEvent_Ramped) {\n\t\t\t\toffset = event.eventValues.ramp.startBufferOffset +\n\t\t\t\t\t\t static_cast<SInt32>(event.eventValues.ramp.durationInFrames); // NOLINT\n\n\t\t\t\tif (offset > static_cast<SInt32>(currentStartFrame) &&\n\t\t\t\t\toffset < static_cast<SInt32>(currentEndFrame)) {\n\t\t\t\t\tcurrentEndFrame = static_cast<UInt32>(offset);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst UInt32 framesThisTime = currentEndFrame - currentStartFrame;\n\n\t\t// next, setup the parameter maps to be current for the ramp parameters active during\n\t\t// this time segment...\n\n\t\tfor (const auto& event : inParamList) {\n\t\t\tbool eventFallsInSlice = false;\n\n\t\t\tif (event.eventType == kParameterEvent_Ramped) {\n\t\t\t\tconst auto& ramp = event.eventValues.ramp;\n\t\t\t\teventFallsInSlice =\n\t\t\t\t\tramp.startBufferOffset < static_cast<SInt32>(currentEndFrame) &&\n\t\t\t\t\t(ramp.startBufferOffset + static_cast<SInt32>(ramp.durationInFrames)) >\n\t\t\t\t\t\tstatic_cast<SInt32>(currentStartFrame);\n\t\t\t} else { /* kParameterEvent_Immediate */\n\t\t\t\t// actually, for the same parameter, there may be future immediate events which\n\t\t\t\t// override this one, but it's OK since the event list is sorted in time order,\n\t\t\t\t// we're guaranteed to end up with the current one\n\t\t\t\teventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame;\n\t\t\t}\n\n\t\t\tif (eventFallsInSlice) {\n\t\t\t\tconst auto element = GetElementOrError(event.scope, event.element);\n\n\t\t\t\tif (element) {\n\t\t\t\t\tstd::ignore = element->SetScheduledEvent(event.parameter, event,\n\t\t\t\t\t\tcurrentStartFrame, currentEndFrame - currentStartFrame);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\t// Finally, actually do the processing for this slice.....\n\n\t\tresult =\n\t\t\tProcessScheduledSlice(inUserData, currentStartFrame, framesThisTime, inFramesToProcess);\n\n\t\tif (result != noErr) {\n\t\t\tbreak;\n\t\t}\n\n\t\tframesRemaining -= std::min(framesThisTime, framesRemaining);\n\t\tcurrentStartFrame = currentEndFrame; // now start from where we left off last time\n\t}\n\n\treturn result;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::ResetRenderTime()\n{\n\tmCurrentRenderTime = {};\n\tmCurrentRenderTime.mSampleTime = kNoLastRenderedSampleTime;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::SetWantsRenderThreadID(bool inFlag)\n{\n\tif (inFlag == mWantsRenderThreadID) {\n\t\treturn;\n\t}\n\n\tmWantsRenderThreadID = inFlag;\n\tif (!mWantsRenderThreadID) {\n\t\tmRenderThreadID = {};\n\t};\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DoRender(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, UInt32 inBusNumber, UInt32 inFramesToProcess,\n\tAudioBufferList& ioData) noexcept AUSDK_RTSAFE\n{\n\tconst auto postRender = [this, &ioActionFlags, &inTimeStamp, inBusNumber, inFramesToProcess, &ioData](OSStatus error) AUSDK_RTSAFE_LAMBDA {\n\t\tSetRenderError(error);\n\n\t\tif (mRenderCallbacksTouched) {\n\t\t\tAudioUnitRenderActionFlags flags = ioActionFlags | kAudioUnitRenderAction_PostRender;\n\n\t\t\tif (error != noErr) {\n\t\t\t\tflags |= kAudioUnitRenderAction_PostRenderError;\n\t\t\t}\n\n\t\t\tfor (const RenderCallback& rc : mRenderCallbacks) {\n\t\t\t\trc.mRenderNotify(rc.mRenderNotifyRefCon, &flags, &inTimeStamp, inBusNumber,\n\t\t\t\t\tinFramesToProcess, &ioData);\n\t\t\t}\n\t\t}\n\n\t\t// The vector is being emptied because these events should only apply to this Render cycle,\n\t\t// so anything left over is from a preceding cycle and should be dumped.\n\t\t// New scheduled parameters must be scheduled from the next pre-render callback.\n\t\tif (!mParamEventList.empty()) {\n\t\t\tmParamEventList.clear();\n\t\t}\n\t};\n\n\tconst auto errorExit = [this, postRender](OSStatus error) AUSDK_RTSAFE_LAMBDA {\n\t\tAUSDK_LogError_RT(\"  from %s, render err: %d\", GetLoggingString(), static_cast<int>(error));\n\t\tSetRenderError(error);\n\t\tpostRender(error);\n\t\treturn error;\n\t};\n\n\tOSStatus theError = noErr;\n\n\t[[maybe_unused]] const DenormalDisabler denormalDisabler;\n\n#if AUSDK_LOOSE_RT_SAFETY\n\ttry {\n#endif // AUSDK_LOOSE_RT_SAFETY\n\n\t\tAUSDK_Require(IsInitialized(), errorExit(kAudioUnitErr_Uninitialized));\n\t\tif (inFramesToProcess > mMaxFramesPerSlice) {\n#ifndef AUSDK_NO_LOGGING\n\t\t\tconst UInt64 now = HostTime::Current();\n\t\t\tif (static_cast<double>(now - mLastTimeMessagePrinted) >\n\t\t\t\tmHostTimeFrequency) { // not more than once per second.\n\t\t\t\tmLastTimeMessagePrinted = now;\n\t\t\t\tAUSDK_LogError_RT(\"kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, \"\n\t\t\t\t\t\t\t\t  \"mMaxFramesPerSlice=%u\",\n\t\t\t\t\tstatic_cast<unsigned>(inFramesToProcess),\n\t\t\t\t\tstatic_cast<unsigned>(mMaxFramesPerSlice));\n\t\t\t}\n#endif\n\t\t\treturn errorExit(kAudioUnitErr_TooManyFramesToProcess);\n\t\t}\n\t\tAUSDK_Require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(),\n\t\t\terrorExit(kAudio_ParamError));\n\n\t\tAUOutputElement& output = AUSDK_UnwrapOrReturnError(GetOutputOrError(inBusNumber));\n\t\tif (ASBD::NumberChannelStreams(output.GetStreamFormat()) != ioData.mNumberBuffers) {\n\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\"ioData.mNumberBuffers=%u, \"\n\t\t\t\t\"ASBD::NumberChannelStreams(output.GetStreamFormat())=%u; kAudio_ParamError\",\n\t\t\t\tstatic_cast<unsigned>(ioData.mNumberBuffers),\n\t\t\t\tstatic_cast<unsigned>(ASBD::NumberChannelStreams(output.GetStreamFormat())));\n\t\t\treturn errorExit(kAudio_ParamError);\n\t\t}\n\n\t\tconst unsigned expectedBufferByteSize =\n\t\t\tinFramesToProcess * output.GetStreamFormat().mBytesPerFrame;\n\t\tfor (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {\n\t\t\tAudioBuffer& buf = ioData.mBuffers[ibuf]; // NOLINT\n\t\t\tif (buf.mData != nullptr) {\n\t\t\t\t// only care about the size if the buffer is non-null\n\t\t\t\tif (buf.mDataByteSize < expectedBufferByteSize) {\n\t\t\t\t\t// if the buffer is too small, we cannot render safely. kAudio_ParamError.\n\t\t\t\t\tAUSDK_LogError_RT(\"%u frames, %u bytes/frame, expected %u-byte buffer; \"\n\t\t\t\t\t\t\t\t\t  \"ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError\",\n\t\t\t\t\t\tstatic_cast<unsigned>(inFramesToProcess),\n\t\t\t\t\t\tstatic_cast<unsigned>(output.GetStreamFormat().mBytesPerFrame),\n\t\t\t\t\t\texpectedBufferByteSize, ibuf, static_cast<unsigned>(buf.mDataByteSize));\n\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t}\n\t\t\t\t// Some clients incorrectly pass bigger buffers than expectedBufferByteSize.\n\t\t\t\t// We will generally set the buffer size at the end of rendering, before we return.\n\t\t\t\t// However we should ensure that no one, DURING rendering, READS a\n\t\t\t\t// potentially incorrect size. This can lead to doing too much work, or\n\t\t\t\t// reading past the end of an input buffer into unmapped memory.\n\t\t\t\tbuf.mDataByteSize = expectedBufferByteSize;\n\t\t\t}\n\t\t}\n\n\t\tif (WantsRenderThreadID()) {\n\t\t\tmRenderThreadID = AUSDK_RT_UNSAFE(std::this_thread::get_id());\n\t\t}\n\n\t\tif (mRenderCallbacksTouched) {\n\t\t\tmRenderCallbacks.Update();\n\n\t\t\tAudioUnitRenderActionFlags flags = ioActionFlags | kAudioUnitRenderAction_PreRender;\n\t\t\tfor (const RenderCallback& rc : mRenderCallbacks) {\n\t\t\t\trc.mRenderNotify(rc.mRenderNotifyRefCon, &flags, &inTimeStamp, inBusNumber,\n\t\t\t\t\tinFramesToProcess, &ioData);\n\t\t\t}\n\t\t}\n\n\t\ttheError =\n\t\t\tDoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData);\n\t\tpostRender(theError);\n\n#if AUSDK_LOOSE_RT_SAFETY\n\t\tAUSDK_RT_UNSAFE_BEGIN(\"exception-catching under loose safety model\")\n\t} catch (const ausdk::AUException& err) {\n\t\treturn errorExit(err.mError);\n\t} catch (const OSStatus& err) {\n\t\treturn errorExit(err);\n\t} catch (...) {\n\t\treturn errorExit(-1);\n\t}\n\tAUSDK_RT_UNSAFE_END\n#endif // AUSDK_LOOSE_RT_SAFETY\n\n\treturn theError;\n}\n\ninline bool CheckRenderArgs(AudioUnitRenderActionFlags flags)\n{\n\treturn (flags & kAudioUnitRenderAction_DoNotCheckRenderArgs) == 0u;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::DoProcess(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, UInt32 inFramesToProcess,\n\tAudioBufferList& ioData) noexcept AUSDK_RTSAFE\n{\n\tconst auto errorExit = [this](OSStatus error) AUSDK_RTSAFE_LAMBDA {\n\t\tAUSDK_LogError_RT(\n\t\t\t\"  from %s, process err: %d\", GetLoggingString(), static_cast<int>(error));\n\t\tSetRenderError(error);\n\t\treturn error;\n\t};\n\n\tOSStatus theError = noErr;\n\n\t[[maybe_unused]] const DenormalDisabler denormalDisabler;\n\n#if AUSDK_LOOSE_RT_SAFETY\n\ttry {\n#endif // AUSDK_LOOSE_RT_SAFETY\n\t\tif (CheckRenderArgs(ioActionFlags)) {\n\t\t\tAUSDK_Require(IsInitialized(), errorExit(kAudioUnitErr_Uninitialized));\n\t\t\tAUSDK_Require(inFramesToProcess <= mMaxFramesPerSlice,\n\t\t\t\terrorExit(kAudioUnitErr_TooManyFramesToProcess));\n\t\t\tAUSDK_Require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(),\n\t\t\t\terrorExit(kAudio_ParamError));\n\n\t\t\tAUInputElement& input = AUSDK_UnwrapOrReturnError(GetInputOrError(0));\n\t\t\tif (ASBD::NumberChannelStreams(input.GetStreamFormat()) != ioData.mNumberBuffers) {\n\t\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\t\"ioData.mNumberBuffers=%u, \"\n\t\t\t\t\t\"ASBD::NumberChannelStreams(input.GetStreamFormat())=%u; kAudio_ParamError\",\n\t\t\t\t\tstatic_cast<unsigned>(ioData.mNumberBuffers),\n\t\t\t\t\tstatic_cast<unsigned>(ASBD::NumberChannelStreams(input.GetStreamFormat())));\n\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t}\n\n\t\t\tconst unsigned expectedBufferByteSize =\n\t\t\t\tinFramesToProcess * input.GetStreamFormat().mBytesPerFrame;\n\t\t\tfor (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {\n\t\t\t\tAudioBuffer& buf = ioData.mBuffers[ibuf]; // NOLINT\n\t\t\t\tif (buf.mData != nullptr) {\n\t\t\t\t\t// only care about the size if the buffer is non-null\n\t\t\t\t\tif (buf.mDataByteSize < expectedBufferByteSize) {\n\t\t\t\t\t\t// if the buffer is too small, we cannot render safely. kAudio_ParamError.\n\t\t\t\t\t\tAUSDK_LogError_RT(\"%u frames, %u bytes/frame, expected %u-byte buffer; \"\n\t\t\t\t\t\t\t\t\t\t  \"ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError\",\n\t\t\t\t\t\t\tstatic_cast<unsigned>(inFramesToProcess),\n\t\t\t\t\t\t\tstatic_cast<unsigned>(input.GetStreamFormat().mBytesPerFrame),\n\t\t\t\t\t\t\texpectedBufferByteSize, ibuf, static_cast<unsigned>(buf.mDataByteSize));\n\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t}\n\t\t\t\t\t// Some clients incorrectly pass bigger buffers than expectedBufferByteSize.\n\t\t\t\t\t// We will generally set the buffer size at the end of rendering, before we\n\t\t\t\t\t// return. However we should ensure that no one, DURING rendering, READS a\n\t\t\t\t\t// potentially incorrect size. This can lead to doing too much work, or\n\t\t\t\t\t// reading past the end of an input buffer into unmapped memory.\n\t\t\t\t\tbuf.mDataByteSize = expectedBufferByteSize;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (WantsRenderThreadID()) {\n\t\t\tmRenderThreadID = AUSDK_RT_UNSAFE(std::this_thread::get_id());\n\t\t}\n\n\t\tif (NeedsToRender(inTimeStamp)) {\n\t\t\ttheError = ProcessBufferLists(ioActionFlags, ioData, ioData, inFramesToProcess);\n\t\t} else {\n\t\t\ttheError = noErr;\n\t\t}\n#if AUSDK_LOOSE_RT_SAFETY\n\t\tAUSDK_RT_UNSAFE_BEGIN(\"exception-catching under loose safety model\")\n\t} catch (const ausdk::AUException& err) {\n\t\treturn errorExit(err.mError);\n\t} catch (const OSStatus& err) {\n\t\treturn errorExit(err);\n\t} catch (...) {\n\t\treturn errorExit(-1);\n\t}\n\tAUSDK_RT_UNSAFE_END\n#endif // AUSDK_LOOSE_RT_SAFETY\n\treturn theError;\n}\n\nOSStatus AUBase::DoProcessMultiple(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, UInt32 inFramesToProcess, UInt32 inNumberInputBufferLists,\n\tconst AudioBufferList** inInputBufferLists, UInt32 inNumberOutputBufferLists,\n\tAudioBufferList** ioOutputBufferLists) noexcept AUSDK_RTSAFE\n{\n\tconst auto errorExit = [this](OSStatus error) AUSDK_RTSAFE_LAMBDA {\n\t\tAUSDK_LogError_RT(\n\t\t\t\"  from %s, processmultiple err: %d\", GetLoggingString(), static_cast<int>(error));\n\t\tSetRenderError(error);\n\t\treturn error;\n\t};\n\n\tOSStatus theError = noErr;\n\n\t[[maybe_unused]] const DenormalDisabler denormalDisabler;\n\n#if AUSDK_LOOSE_RT_SAFETY\n\ttry {\n#endif // AUSDK_LOOSE_RT_SAFETY\n\t\tif (CheckRenderArgs(ioActionFlags)) {\n\t\t\tAUSDK_Require(IsInitialized(), errorExit(kAudioUnitErr_Uninitialized));\n\t\t\tAUSDK_Require(inFramesToProcess <= mMaxFramesPerSlice,\n\t\t\t\terrorExit(kAudioUnitErr_TooManyFramesToProcess));\n\t\t\tAUSDK_Require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(),\n\t\t\t\terrorExit(kAudio_ParamError));\n\n\t\t\tfor (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) {\n\t\t\t\tif (inInputBufferLists[ibl] != nullptr) { // NOLINT\n\t\t\t\t\tAUInputElement& input = AUSDK_UnwrapOrReturnError(GetInputOrError(ibl));\n\t\t\t\t\tconst unsigned expectedBufferByteSize =\n\t\t\t\t\t\tinFramesToProcess * input.GetStreamFormat().mBytesPerFrame;\n\n\t\t\t\t\tif (ASBD::NumberChannelStreams(input.GetStreamFormat()) !=\n\t\t\t\t\t\tinInputBufferLists[ibl]->mNumberBuffers) { // NOLINT\n\t\t\t\t\t\tAUSDK_LogError_RT(\"inInputBufferLists[%u]->mNumberBuffers=%u, \"\n\t\t\t\t\t\t\t\t\t\t  \"ASBD::NumberChannelStreams(input.GetStreamFormat())=%u; \"\n\t\t\t\t\t\t\t\t\t\t  \"kAudio_ParamError\",\n\t\t\t\t\t\t\tibl, static_cast<unsigned>(inInputBufferLists[ibl]->mNumberBuffers),\n\t\t\t\t\t\t\tstatic_cast<unsigned>(\n\t\t\t\t\t\t\t\tASBD::NumberChannelStreams(input.GetStreamFormat())));\n\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (unsigned ibuf = 0;\n\t\t\t\t\t\tibuf < inInputBufferLists[ibl]->mNumberBuffers; // NOLINT\n\t\t\t\t\t\t++ibuf) {\n\t\t\t\t\t\tconst AudioBuffer& buf = inInputBufferLists[ibl]->mBuffers[ibuf]; // NOLINT\n\t\t\t\t\t\tif (buf.mData != nullptr) {\n\t\t\t\t\t\t\tif (buf.mDataByteSize < expectedBufferByteSize) {\n\t\t\t\t\t\t\t\t// the buffer is too small\n\t\t\t\t\t\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\t\t\t\t\t\"%u frames, %u bytes/frame, expected %u-byte buffer; \"\n\t\t\t\t\t\t\t\t\t\"inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; \"\n\t\t\t\t\t\t\t\t\t\"kAudio_ParamError\",\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(inFramesToProcess),\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(input.GetStreamFormat().mBytesPerFrame),\n\t\t\t\t\t\t\t\t\texpectedBufferByteSize, ibl, ibuf,\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(buf.mDataByteSize));\n\t\t\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// the buffer must exist\n\t\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// skip NULL input audio buffer list\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) {\n\t\t\t\tif (ioOutputBufferLists[obl] != nullptr) { // NOLINT\n\t\t\t\t\tAUOutputElement& output = AUSDK_UnwrapOrReturnError(GetOutputOrError(obl));\n\t\t\t\t\tconst unsigned expectedBufferByteSize =\n\t\t\t\t\t\tinFramesToProcess * output.GetStreamFormat().mBytesPerFrame;\n\n\t\t\t\t\tif (ASBD::NumberChannelStreams(output.GetStreamFormat()) !=\n\t\t\t\t\t\tioOutputBufferLists[obl]->mNumberBuffers) { // NOLINT\n\t\t\t\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\t\t\t\"ioOutputBufferLists[%u]->mNumberBuffers=%u, \"\n\t\t\t\t\t\t\t\"ASBD::NumberChannelStreams(output.GetStreamFormat())=%u; \"\n\t\t\t\t\t\t\t\"kAudio_ParamError\",\n\t\t\t\t\t\t\tobl, static_cast<unsigned>(ioOutputBufferLists[obl]->mNumberBuffers),\n\t\t\t\t\t\t\tstatic_cast<unsigned>(\n\t\t\t\t\t\t\t\tASBD::NumberChannelStreams(output.GetStreamFormat())));\n\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (unsigned obuf = 0;\n\t\t\t\t\t\tobuf < ioOutputBufferLists[obl]->mNumberBuffers; // NOLINT\n\t\t\t\t\t\t++obuf) {\n\t\t\t\t\t\tAudioBuffer& buf = ioOutputBufferLists[obl]->mBuffers[obuf]; // NOLINT\n\t\t\t\t\t\tif (buf.mData != nullptr) {\n\t\t\t\t\t\t\t// only care about the size if the buffer is non-null\n\t\t\t\t\t\t\tif (buf.mDataByteSize < expectedBufferByteSize) {\n\t\t\t\t\t\t\t\t// if the buffer is too small, we cannot render safely.\n\t\t\t\t\t\t\t\t// kAudio_ParamError.\n\t\t\t\t\t\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\t\t\t\t\t\"%u frames, %u bytes/frame, expected %u-byte buffer; \"\n\t\t\t\t\t\t\t\t\t\"ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; \"\n\t\t\t\t\t\t\t\t\t\"kAudio_ParamError\",\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(inFramesToProcess),\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(output.GetStreamFormat().mBytesPerFrame),\n\t\t\t\t\t\t\t\t\texpectedBufferByteSize, obl, obuf,\n\t\t\t\t\t\t\t\t\tstatic_cast<unsigned>(buf.mDataByteSize));\n\t\t\t\t\t\t\t\treturn errorExit(kAudio_ParamError);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Some clients incorrectly pass bigger buffers than\n\t\t\t\t\t\t\t// expectedBufferByteSize. We will generally set the buffer size at the\n\t\t\t\t\t\t\t// end of rendering, before we return. However we should ensure that no\n\t\t\t\t\t\t\t// one, DURING rendering, READS a potentially incorrect size. This can\n\t\t\t\t\t\t\t// lead to doing too much work, or reading past the end of an input\n\t\t\t\t\t\t\t// buffer into unmapped memory.\n\t\t\t\t\t\t\tbuf.mDataByteSize = expectedBufferByteSize;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// skip NULL output audio buffer list\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (WantsRenderThreadID()) {\n\t\t\tmRenderThreadID = AUSDK_RT_UNSAFE(std::this_thread::get_id());\n\t\t}\n\n\t\tif (NeedsToRender(inTimeStamp)) {\n\t\t\ttheError = ProcessMultipleBufferLists(ioActionFlags, inFramesToProcess,\n\t\t\t\tinNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists,\n\t\t\t\tioOutputBufferLists);\n\t\t} else {\n\t\t\ttheError = noErr;\n\t\t}\n#if AUSDK_LOOSE_RT_SAFETY\n\t\tAUSDK_RT_UNSAFE_BEGIN(\"exception-catching under loose safety model\")\n\t} catch (const ausdk::AUException& err) {\n\t\treturn errorExit(err.mError);\n\t} catch (const OSStatus& err) {\n\t\treturn errorExit(err);\n\t} catch (...) {\n\t\treturn errorExit(-1);\n\t}\n\tAUSDK_RT_UNSAFE_END\n#endif // AUSDK_LOOSE_RT_SAFETY\n\treturn theError;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::SetInputCallback(\n\tUInt32 inPropertyID, AudioUnitElement inElement, AURenderCallback inProc, void* inRefCon)\n{\n\tauto& input = Input(inElement); // may throw\n\n\tinput.SetInputCallback(inProc, inRefCon);\n\tPropertyChanged(inPropertyID, kAudioUnitScope_Input, inElement);\n\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\n// NOLINTNEXTLINE(misc-no-recursion) with DispatchSetProperty\nOSStatus AUBase::SetConnection(const AudioUnitConnection& inConnection)\n{\n\tauto& input = Input(inConnection.destInputNumber); // may throw\n\n\tif (inConnection.sourceAudioUnit != nullptr) {\n\t\t// connecting, not disconnecting\n\t\tAudioStreamBasicDescription sourceDesc;\n\t\tUInt32 size = sizeof(AudioStreamBasicDescription);\n\t\tAUSDK_Require_noerr(\n\t\t\tAudioUnitGetProperty(inConnection.sourceAudioUnit, kAudioUnitProperty_StreamFormat,\n\t\t\t\tkAudioUnitScope_Output, inConnection.sourceOutputNumber, &sourceDesc, &size));\n\t\tAUSDK_Require_noerr(\n\t\t\tDispatchSetProperty(kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,\n\t\t\t\tinConnection.destInputNumber, &sourceDesc, sizeof(AudioStreamBasicDescription)));\n\t}\n\tinput.SetConnection(inConnection);\n\n\tPropertyChanged(\n\t\tkAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, inConnection.destInputNumber);\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nUInt32 AUBase::SupportedNumChannels(const AUChannelInfo** /*outInfo*/) { return 0; }\n\n//_____________________________________________________________________________\n//\nbool AUBase::ValidFormat(AudioUnitScope /*inScope*/, AudioUnitElement /*inElement*/,\n\tconst AudioStreamBasicDescription& inNewFormat)\n{\n\treturn ASBD::IsCommonFloat32(inNewFormat) &&\n\t\t   (!ASBD::IsInterleaved(inNewFormat) || inNewFormat.mChannelsPerFrame == 1);\n}\n\n//_____________________________________________________________________________\n//\nbool AUBase::IsStreamFormatWritable(AudioUnitScope scope, AudioUnitElement element)\n{\n\tswitch (scope) {\n\tcase kAudioUnitScope_Input: {\n\t\tconst auto& input = Input(element);\n\t\tif (input.HasConnection()) {\n\t\t\treturn false; // can't write format when input comes from connection\n\t\t}\n\t\t[[fallthrough]];\n\t}\n\tcase kAudioUnitScope_Output:\n\t\treturn StreamFormatWritable(scope, element);\n\n\t\t// #warning \"aliasing of global scope format should be pushed to subclasses\"\n\tcase kAudioUnitScope_Global:\n\t\treturn StreamFormatWritable(kAudioUnitScope_Output, 0);\n\tdefault:\n\t\tbreak;\n\t}\n\treturn false;\n}\n\n//_____________________________________________________________________________\n//\nAudioStreamBasicDescription AUBase::GetStreamFormat(\n\tAudioUnitScope inScope, AudioUnitElement inElement) AUSDK_RTSAFE_LOOSE\n{\n\t// #warning \"aliasing of global scope format should be pushed to subclasses\"\n\tAUIOElement* element = nullptr;\n\n\tswitch (inScope) {\n\tcase kAudioUnitScope_Input:\n\t\telement = Inputs().GetIOElement(inElement);\n\t\tbreak;\n\tcase kAudioUnitScope_Output:\n\t\telement = Outputs().GetIOElement(inElement);\n\t\tbreak;\n\tcase kAudioUnitScope_Global: // global stream description is an alias for that of output 0\n\t\telement = Outputs().GetIOElement(0);\n\t\tbreak;\n\tdefault:\n\t\tThrow(kAudioUnitErr_InvalidScope);\n\t}\n\treturn element->GetStreamFormat();\n}\n\nOSStatus AUBase::SetBusCount(AudioUnitScope inScope, UInt32 inCount)\n{\n\tAUSDK_Require(!IsInitialized(), kAudioUnitErr_Initialized);\n\n\tGetScope(inScope).SetNumberOfElements(inCount);\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,\n\tconst AudioStreamBasicDescription& inPrevFormat, const AudioStreamBasicDescription& inNewFormat)\n{\n\tif (ASBD::IsEqual(inNewFormat, inPrevFormat)) {\n\t\treturn noErr;\n\t}\n\n\t// #warning \"aliasing of global scope format should be pushed to subclasses\"\n\tAUIOElement* element = nullptr;\n\n\tswitch (inScope) {\n\tcase kAudioUnitScope_Input:\n\t\telement = Inputs().GetIOElement(inElement);\n\t\tbreak;\n\tcase kAudioUnitScope_Output:\n\t\telement = Outputs().GetIOElement(inElement);\n\t\tbreak;\n\tcase kAudioUnitScope_Global:\n\t\telement = Outputs().GetIOElement(0);\n\t\tbreak;\n\tdefault:\n\t\tThrow(kAudioUnitErr_InvalidScope);\n\t}\n\telement->SetStreamFormat(inNewFormat);\n\tPropertyChanged(kAudioUnitProperty_StreamFormat, inScope, inElement);\n\treturn noErr;\n}\n\nstd::vector<AudioChannelLayoutTag> AUBase::GetChannelLayoutTags(\n\tAudioUnitScope inScope, AudioUnitElement inElement)\n{\n\treturn IOElement(inScope, inElement).GetChannelLayoutTags();\n}\n\nUInt32 AUBase::GetAudioChannelLayout(AudioUnitScope inScope, AudioUnitElement inElement,\n\tAudioChannelLayout* outLayoutPtr, bool& outWritable)\n{\n\tauto& element = IOElement(inScope, inElement);\n\treturn element.GetAudioChannelLayout(outLayoutPtr, outWritable);\n}\n\nOSStatus AUBase::RemoveAudioChannelLayout(AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\tauto& element = IOElement(inScope, inElement);\n\tbool writable = false;\n\tif (element.GetAudioChannelLayout(nullptr, writable) > 0) {\n\t\treturn element.RemoveAudioChannelLayout();\n\t}\n\treturn noErr;\n}\n\nOSStatus AUBase::SetAudioChannelLayout(\n\tAudioUnitScope inScope, AudioUnitElement inElement, const AudioChannelLayout* inLayout)\n{\n\tauto& element = IOElement(inScope, inElement);\n\n\t// the num channels of the layout HAS TO MATCH the current channels of the Element's stream\n\t// format\n\tconst UInt32 currentChannels = element.GetStreamFormat().mChannelsPerFrame;\n\tconst UInt32 numChannelsInLayout = AUChannelLayout::NumberChannels(*inLayout);\n\tAUSDK_Require(currentChannels == numChannelsInLayout, kAudioUnitErr_InvalidPropertyValue);\n\n\tconst auto tags = GetChannelLayoutTags(inScope, inElement);\n\tAUSDK_Require(!tags.empty(), kAudioUnitErr_InvalidProperty);\n\tconst auto iter = std::ranges::find_if(tags, [inTag = inLayout->mChannelLayoutTag](auto tag) {\n\t\treturn tag == inTag || tag == kAudioChannelLayoutTag_UseChannelDescriptions;\n\t});\n\tAUSDK_Require(iter != tags.end(), kAudioUnitErr_InvalidPropertyValue);\n\n\treturn element.SetAudioChannelLayout(*inLayout);\n}\n\nconstexpr int kCurrentSavedStateVersion = 0;\n\nstatic void AddNumToDictionary(CFMutableDictionaryRef dict, CFStringRef key, SInt32 value)\n{\n\tconst CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value);\n\tCFDictionarySetValue(dict, key, num);\n\tCFRelease(num);\n}\n\n// NOLINTNEXTLINE(misc-no-recursion) with DispatchGetProperty\nOSStatus AUBase::SaveState(CFPropertyListRef* outData)\n{\n\tconst AudioComponentDescription desc = GetComponentDescription();\n\n\tauto dict = Owned<CFMutableDictionaryRef>::from_create(CFDictionaryCreateMutable(\n\t\tnullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));\n\n\t// first step -> save the version to the data ref\n\tSInt32 value = kCurrentSavedStateVersion;\n\tAddNumToDictionary(*dict, CFSTR(kAUPresetVersionKey), value);\n\n\t// second step -> save the component type, subtype, manu to the data ref\n\tvalue = static_cast<SInt32>(desc.componentType);\n\tAddNumToDictionary(*dict, CFSTR(kAUPresetTypeKey), value);\n\n\tvalue = static_cast<SInt32>(desc.componentSubType);\n\tAddNumToDictionary(*dict, CFSTR(kAUPresetSubtypeKey), value);\n\n\tvalue = static_cast<SInt32>(desc.componentManufacturer);\n\tAddNumToDictionary(*dict, CFSTR(kAUPresetManufacturerKey), value);\n\n\t// fourth step -> save the state of all parameters on all scopes and elements\n\tauto data = Owned<CFMutableDataRef>::from_create(CFDataCreateMutable(nullptr, 0));\n\tfor (AudioUnitScope iscope = 0; iscope < 3; ++iscope) {\n\t\tconst auto& scope = GetScope(iscope);\n\t\tscope.SaveState(*data);\n\t}\n\n\tSaveExtendedScopes(*data);\n\n\t// save all this in the data section of the dictionary\n\tCFDictionarySetValue(*dict, CFSTR(kAUPresetDataKey), *data);\n\tdata = nullptr; // data can be large-ish, so destroy it now.\n\n\t// OK - now we're going to do some properties\n\t// save the preset name...\n\tCFDictionarySetValue(*dict, CFSTR(kAUPresetNameKey), mCurrentPreset.presetName);\n\n\t// Does the unit support the RenderQuality property - if so, save it...\n\tOSStatus result =\n\t\tDispatchGetProperty(kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, 0, &value);\n\n\tif (result == noErr) {\n\t\tAddNumToDictionary(*dict, CFSTR(kAUPresetRenderQualityKey), value);\n\t}\n\n\t// Do we have any element names for any of our scopes?\n\t// first check to see if we have any names...\n\tbool foundName = false;\n\tfor (AudioUnitScope i = 0; i < kNumScopes; ++i) {\n\t\tfoundName = GetScope(i).HasElementWithName();\n\t\tif (foundName) {\n\t\t\tbreak;\n\t\t}\n\t}\n\t// OK - we found a name away we go...\n\tif (foundName) {\n\t\tauto nameDict = Owned<CFMutableDictionaryRef>::from_create(CFDictionaryCreateMutable(\n\t\t\tnullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));\n\t\tfor (AudioUnitScope i = 0; i < kNumScopes; ++i) {\n\t\t\tGetScope(i).AddElementNamesToDict(*nameDict);\n\t\t}\n\n\t\tCFDictionarySetValue(*dict, CFSTR(kAUPresetElementNameKey), *nameDict);\n\t}\n\n\t// we're done!!!\n\t*outData = static_cast<CFPropertyListRef>(dict.release()); // transfer ownership\n\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\n// NOLINTNEXTLINE(misc-no-recursion) with DispatchSetProperty\nOSStatus AUBase::RestoreState(CFPropertyListRef plist)\n{\n\tAUSDK_Require(\n\t\tCFGetTypeID(plist) == CFDictionaryGetTypeID(), kAudioUnitErr_InvalidPropertyValue);\n\n\tconst AudioComponentDescription desc = GetComponentDescription();\n\n\tconst auto* const dict = static_cast<CFDictionaryRef>(plist);\n\n\t// zeroeth step - make sure the Part key is NOT present, as this method is used\n\t// to restore the GLOBAL state of the dictionary\n\tAUSDK_Require(!CFDictionaryContainsKey(dict, CFSTR(kAUPresetPartKey)),\n\t\tkAudioUnitErr_InvalidPropertyValue);\n\n\t// first step -> check the saved version in the data ref\n\t// at this point we're only dealing with version==0\n\tconst auto* cfNum =\n\t\tstatic_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetVersionKey)));\n\tAUSDK_Require(cfNum != nullptr, kAudioUnitErr_InvalidPropertyValue);\n\tAUSDK_Require(CFGetTypeID(cfNum) == CFNumberGetTypeID(), kAudioUnitErr_InvalidPropertyValue);\n\tSInt32 value = 0;\n\tCFNumberGetValue(cfNum, kCFNumberSInt32Type, &value);\n\tAUSDK_Require(value == kCurrentSavedStateVersion, kAudioUnitErr_InvalidPropertyValue);\n\n\t// second step -> check that this data belongs to this kind of audio unit\n\t// by checking the component subtype and manuID\n\t// We're not checking the type, since there may be different versions (effect, format-converter,\n\t// offline) of essentially the same AU\n\tcfNum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetSubtypeKey)));\n\tAUSDK_Require(cfNum != nullptr, kAudioUnitErr_InvalidPropertyValue);\n\tAUSDK_Require(CFGetTypeID(cfNum) == CFNumberGetTypeID(), kAudioUnitErr_InvalidPropertyValue);\n\tCFNumberGetValue(cfNum, kCFNumberSInt32Type, &value);\n\tAUSDK_Require(\n\t\tstatic_cast<UInt32>(value) == desc.componentSubType, kAudioUnitErr_InvalidPropertyValue);\n\n\tcfNum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetManufacturerKey)));\n\tAUSDK_Require(cfNum != nullptr, kAudioUnitErr_InvalidPropertyValue);\n\tAUSDK_Require(CFGetTypeID(cfNum) == CFNumberGetTypeID(), kAudioUnitErr_InvalidPropertyValue);\n\tCFNumberGetValue(cfNum, kCFNumberSInt32Type, &value);\n\tAUSDK_Require(static_cast<UInt32>(value) == desc.componentManufacturer,\n\t\tkAudioUnitErr_InvalidPropertyValue);\n\n\t// fourth step -> restore the state of all of the parameters for each scope and element\n\tconst auto* const data =\n\t\tstatic_cast<CFDataRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetDataKey)));\n\tif ((data != nullptr) && (CFGetTypeID(data) == CFDataGetTypeID())) {\n\t\tconst UInt8* p = CFDataGetBytePtr(data);\n\t\tconst UInt8* const pend = p + CFDataGetLength(data); // NOLINT\n\n\t\twhile (p < pend) {\n\t\t\tconst auto scopeIndex = DeserializeBigUInt32AndAdvance(p);\n\t\t\tconst auto& scope = GetScope(scopeIndex);\n\t\t\tp = scope.RestoreState(p);\n\t\t}\n\t}\n\n\t// OK - now we're going to do some properties\n\t// restore the preset name...\n\tconst auto* const name =\n\t\tstatic_cast<CFStringRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetNameKey)));\n\tif (mCurrentPreset.presetName != nullptr) {\n\t\tCFRelease(mCurrentPreset.presetName);\n\t}\n\tif ((name != nullptr) && (CFGetTypeID(name) == CFStringGetTypeID())) {\n\t\tmCurrentPreset.presetName = name;\n\t\tmCurrentPreset.presetNumber = -1;\n\t} else { // no name entry make the default one\n\t\tmCurrentPreset.presetName = GetPresetDefaultName();\n\t\tmCurrentPreset.presetNumber = -1;\n\t}\n\n\tCFRetain(mCurrentPreset.presetName);\n\tPropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);\n\n\t// Does the dict contain render quality information?\n\tcfNum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetRenderQualityKey)));\n\tif (cfNum && (CFGetTypeID(cfNum) == CFNumberGetTypeID())) {\n\t\tCFNumberGetValue(cfNum, kCFNumberSInt32Type, &value);\n\t\tDispatchSetProperty(\n\t\t\tkAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, 0, &value, sizeof(value));\n\t}\n\n\t// Do we have any element names for any of our scopes?\n\tconst auto nameDict =\n\t\tstatic_cast<CFDictionaryRef>(CFDictionaryGetValue(dict, CFSTR(kAUPresetElementNameKey)));\n\tif (nameDict && (CFGetTypeID(nameDict) == CFDictionaryGetTypeID())) {\n\t\tfor (AudioUnitScope i = 0; i < kNumScopes; ++i) {\n\t\t\tconst CFStringRef key = CFStringCreateWithFormat(\n\t\t\t\tnullptr, nullptr, CFSTR(\"%u\"), static_cast<unsigned>(i)); // NOLINT\n\t\t\tconst auto elementDict =\n\t\t\t\tstatic_cast<CFDictionaryRef>(CFDictionaryGetValue(nameDict, key));\n\t\t\tif (elementDict && (CFGetTypeID(elementDict) == CFDictionaryGetTypeID())) {\n\t\t\t\tconst auto restoredElements = GetScope(i).RestoreElementNames(elementDict);\n\t\t\t\tfor (const auto& element : restoredElements) {\n\t\t\t\t\tPropertyChanged(kAudioUnitProperty_ElementName, i, element);\n\t\t\t\t}\n\t\t\t}\n\t\t\tCFRelease(key);\n\t\t}\n\t}\n\n\treturn noErr;\n}\n\nOSStatus AUBase::GetPresets(CFArrayRef* /*outData*/) const { return kAudioUnitErr_InvalidProperty; }\n\nOSStatus AUBase::NewFactoryPresetSet(const AUPreset& /*inNewFactoryPreset*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\nOSStatus AUBase::NewCustomPresetSet(const AUPreset& inNewCustomPreset)\n{\n\tCFRelease(mCurrentPreset.presetName);\n\tmCurrentPreset = inNewCustomPreset;\n\tCFRetain(mCurrentPreset.presetName);\n\treturn noErr;\n}\n\n// set the default preset for the unit -> the number of the preset MUST be >= 0\n// and the name should be valid, or the preset WON'T take\nbool AUBase::SetAFactoryPresetAsCurrent(const AUPreset& inPreset)\n{\n\tif (inPreset.presetNumber < 0 || inPreset.presetName == nullptr) {\n\t\treturn false;\n\t}\n\tCFRelease(mCurrentPreset.presetName);\n\tmCurrentPreset = inPreset;\n\tCFRetain(mCurrentPreset.presetName);\n\treturn true;\n}\n\nbool AUBase::HasIcon()\n{\n#if AUSDK_HAVE_UI\n\tconst CFURLRef url = CopyIconLocation();\n\tif (url != nullptr) {\n\t\tCFRelease(url);\n\t\treturn true;\n\t}\n#endif // AUSDK_HAVE_UI\n\treturn false;\n}\n\n#if AUSDK_HAVE_UI\nCFURLRef AUBase::CopyIconLocation() { return nullptr; }\n#endif // AUSDK_HAVE_UI\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetParameterList(\n\tAudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters)\n{\n\tconst auto& scope = GetScope(inScope);\n\tAUElement* elementWithMostParameters = nullptr;\n\tUInt32 maxNumParams = 0;\n\n\tconst UInt32 nElems = scope.GetNumberOfElements();\n\tfor (UInt32 ielem = 0; ielem < nElems; ++ielem) {\n\t\tAUElement* const element = scope.GetElement(ielem);\n\t\tconst UInt32 nParams = element->GetNumberOfParameters();\n\t\tif (nParams > maxNumParams) {\n\t\t\tmaxNumParams = nParams;\n\t\t\telementWithMostParameters = element;\n\t\t}\n\t}\n\n\tif (outParameterList != nullptr && elementWithMostParameters != nullptr) {\n\t\telementWithMostParameters->GetParameterList(outParameterList);\n\t}\n\n\toutNumParameters = maxNumParams;\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetParameterInfo(AudioUnitScope /*inScope*/,\n\tAudioUnitParameterID /*inParameterID*/, AudioUnitParameterInfo& /*outParameterInfo*/)\n{\n\treturn kAudioUnitErr_InvalidParameter;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetParameterValueStrings(\n\tAudioUnitScope /*inScope*/, AudioUnitParameterID /*inParameterID*/, CFArrayRef* /*outStrings*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::GetParameterHistoryInfo(AudioUnitScope /*inScope*/,\n\tAudioUnitParameterID /*inParameterID*/, Float32& /*outUpdatesPerSecond*/,\n\tFloat32& /*outHistoryDurationInSeconds*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n\n//_____________________________________________________________________________\n//\nOSStatus AUBase::CopyClumpName(AudioUnitScope /*inScope*/, UInt32 /*inClumpID*/,\n\tUInt32 /*inDesiredNameLength*/, CFStringRef* /*outClumpName*/)\n{\n\treturn kAudioUnitErr_InvalidProperty;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUBase::SetNumberOfElements(AudioUnitScope inScope, UInt32 numElements)\n{\n\tif (inScope == kAudioUnitScope_Global && numElements != 1) {\n\t\tThrow(kAudioUnitErr_InvalidScope);\n\t}\n\n\tGetScope(inScope).SetNumberOfElements(numElements);\n}\n\n//_____________________________________________________________________________\n//\nstd::unique_ptr<AUElement> AUBase::CreateElement(AudioUnitScope scope, AudioUnitElement /*element*/)\n{\n\tswitch (scope) {\n\tcase kAudioUnitScope_Global:\n\t\treturn std::make_unique<AUElement>(*this);\n\tcase kAudioUnitScope_Input:\n\t\treturn std::make_unique<AUInputElement>(*this);\n\tcase kAudioUnitScope_Output:\n\t\treturn std::make_unique<AUOutputElement>(*this);\n\tcase kAudioUnitScope_Group:\n\tcase kAudioUnitScope_Part:\n\t\treturn std::make_unique<AUElement>(*this);\n\tdefault:\n\t\tbreak;\n\t}\n\tThrow(kAudioUnitErr_InvalidScope);\n}\n\nconst char* AUBase::GetLoggingString() const noexcept { return mLogString.c_str(); }\n\nstd::string AUBase::CreateLoggingString() const\n{\n\tconst auto desc = GetComponentDescription();\n\tstd::array<char, 32> buf{};\n\t[[maybe_unused]] const int printCount = snprintf(\n\t\tbuf.data(), buf.size(), \"AU (%p): \", static_cast<void*>(GetComponentInstance())); // NOLINT\n#if DEBUG\n\tassert(printCount < static_cast<int>(buf.size()));\n#endif\n\treturn buf.data() + MakeStringFrom4CC(desc.componentType) + '/' +\n\t\t   MakeStringFrom4CC(desc.componentSubType) + '/' +\n\t\t   MakeStringFrom4CC(desc.componentManufacturer);\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUBuffer.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUBuffer.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUBuffer.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <AudioToolbox/AUComponent.h>\n\n#include <cassert>\n#include <cstddef>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\ninline void ThrowBadAlloc()\n{\n\tAUSDK_LogError(\"AUBuffer throwing bad_alloc\");\n\tthrow std::bad_alloc();\n}\n\n// x: number to be rounded; y: the power of 2 to which to round\nconstexpr uint32_t RoundUpToMultipleOfPowerOf2(uint32_t x, uint32_t y) noexcept\n{\n\tconst uint32_t mask = y - 1u;\n#if DEBUG\n\tassert((mask & y) == 0u); // verifies that y is a power of 2 NOLINT\n#endif\n\treturn (x + mask) & ~mask;\n}\n\n// a * b + c\nstatic UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c)\n{\n\tif (a == 0 || b == 0) {\n\t\treturn c; // prevent zero divide\n\t}\n\n\tif (a > (0xFFFFFFFF - c) / b) { // NOLINT magic\n\t\tThrowBadAlloc();\n\t}\n\n\treturn a * b + c;\n}\n\nAllocatedBuffer* BufferAllocator::Allocate(\n\tUInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 /*reservedFlags*/)\n{\n\tconstexpr size_t kAlignment = 16;\n\tconstexpr size_t kMaxBufferListSize = 65536;\n\n\t// Check for a reasonable number of buffers (obviate a more complicated check with offsetof).\n\tif (numberBuffers > kMaxBufferListSize / sizeof(AudioBuffer)) {\n\t\tthrow std::out_of_range(\"AudioBuffers::Allocate: Too many buffers\");\n\t}\n\n\tmaxBytesPerBuffer = RoundUpToMultipleOfPowerOf2(maxBytesPerBuffer, kAlignment);\n\n\tconst auto bufferDataSize = SafeMultiplyAddUInt32(numberBuffers, maxBytesPerBuffer, 0);\n\tvoid* bufferData = nullptr;\n\tif (bufferDataSize > 0) {\n\t\tbufferData = malloc(bufferDataSize);\n\t\t// don't use calloc(); it might not actually touch the memory and cause a VM fault later\n\t\tmemset(bufferData, 0, bufferDataSize);\n\t}\n\n\tconst auto implSize = static_cast<uint32_t>(\n\t\toffsetof(AllocatedBuffer, mAudioBufferList.mBuffers[std::max(UInt32(1), numberBuffers)]));\n\tauto* const implMem = malloc(implSize);\n\tauto* const allocatedBuffer = new (implMem)\n\t\tAllocatedBuffer{ numberBuffers, maxBytesPerBuffer, implSize, bufferDataSize, bufferData };\n\tallocatedBuffer->mAudioBufferList.mNumberBuffers = numberBuffers;\n\treturn allocatedBuffer;\n}\n\nvoid BufferAllocator::Deallocate(AllocatedBuffer* allocatedBuffer)\n{\n\tif (allocatedBuffer->mBufferData != nullptr) {\n\t\tfree(allocatedBuffer->mBufferData);\n\t}\n\tallocatedBuffer->~AllocatedBuffer();\n\tfree(allocatedBuffer);\n}\n\n\nExpectedPtr<AudioBufferList> AllocatedBuffer::PrepareOrError(\n\tUInt32 channelsPerBuffer, UInt32 bytesPerBuffer) AUSDK_RTSAFE\n{\n\tif (mAudioBufferList.mNumberBuffers > mMaximumNumberBuffers) {\n\t\t// too many buffers\n\t\treturn Unexpected(-1);\n\t}\n\tif (bytesPerBuffer > mMaximumBytesPerBuffer) {\n\t\t// insufficient capacity\n\t\treturn Unexpected(-1);\n\t}\n\n\tauto* ptr = static_cast<std::byte*>(mBufferData);\n\tauto* const ptrend = ptr + mBufferDataSize;\n\n\tfor (UInt32 bufIdx = 0, nBufs = mAudioBufferList.mNumberBuffers; bufIdx < nBufs; ++bufIdx) {\n\t\tauto& buf = mAudioBufferList.mBuffers[bufIdx]; // NOLINT\n\t\tbuf.mNumberChannels = channelsPerBuffer;\n\t\tbuf.mDataByteSize = bytesPerBuffer;\n\t\tbuf.mData = ptr;\n\t\tptr += mMaximumBytesPerBuffer; // NOLINT ptr math\n\t}\n\tif (ptr > ptrend) {\n\t\t// insufficient capacity\n\t\treturn Unexpected(-1);\n\t}\n\treturn mAudioBufferList;\n}\n\nExpectedPtr<AudioBufferList> AllocatedBuffer::PrepareNullOrError(\n\tUInt32 channelsPerBuffer, UInt32 bytesPerBuffer) AUSDK_RTSAFE\n{\n\tif (mAudioBufferList.mNumberBuffers > mMaximumNumberBuffers) {\n\t\t// too many buffers\n\t\treturn Unexpected(-1);\n\t}\n\tfor (UInt32 bufIdx = 0, nBufs = mAudioBufferList.mNumberBuffers; bufIdx < nBufs; ++bufIdx) {\n\t\tauto& buf = mAudioBufferList.mBuffers[bufIdx]; // NOLINT\n\t\tbuf.mNumberChannels = channelsPerBuffer;\n\t\tbuf.mDataByteSize = bytesPerBuffer;\n\t\tbuf.mData = nullptr;\n\t}\n\treturn mAudioBufferList;\n}\n\nExpectedPtr<AudioBufferList> AUBufferList::PrepareBufferOrError(\n\tconst AudioStreamBasicDescription& format, UInt32 nFrames) AUSDK_RTSAFE\n{\n\tif (nFrames > mAllocatedFrames) {\n\t\treturn Unexpected(kAudioUnitErr_TooManyFramesToProcess);\n\t}\n\n\tUInt32 nStreams = 0;\n\tUInt32 channelsPerStream = 0;\n\tif (ASBD::IsInterleaved(format)) {\n\t\tnStreams = 1;\n\t\tchannelsPerStream = format.mChannelsPerFrame;\n\t} else {\n\t\tnStreams = format.mChannelsPerFrame;\n\t\tchannelsPerStream = 1;\n\t}\n\n\tif (nStreams > mAllocatedStreams) {\n\t\treturn Unexpected(kAudioUnitErr_FormatNotSupported);\n\t}\n\tauto maybeABL = mBuffers->PrepareOrError(channelsPerStream, nFrames * format.mBytesPerFrame);\n\tif (maybeABL) {\n\t\tmPtrState = EPtrState::ToMyMemory;\n\t}\n\treturn maybeABL;\n}\n\nExpectedPtr<AudioBufferList> AUBufferList::PrepareNullBufferOrError(\n\tconst AudioStreamBasicDescription& format, UInt32 nFrames) AUSDK_RTSAFE\n{\n\tUInt32 nStreams = 0;\n\tUInt32 channelsPerStream = 0;\n\tif (ASBD::IsInterleaved(format)) {\n\t\tnStreams = 1;\n\t\tchannelsPerStream = format.mChannelsPerFrame;\n\t} else {\n\t\tnStreams = format.mChannelsPerFrame;\n\t\tchannelsPerStream = 1;\n\t}\n\tif (nStreams > mAllocatedStreams) {\n\t\treturn Unexpected(kAudioUnitErr_FormatNotSupported);\n\t}\n\tauto maybeABL =\n\t\tmBuffers->PrepareNullOrError(channelsPerStream, nFrames * format.mBytesPerFrame);\n\tif (maybeABL) {\n\t\tmPtrState = EPtrState::ToExternalMemory;\n\t}\n\treturn maybeABL;\n}\n\nvoid AUBufferList::Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames)\n{\n\tauto& alloc = BufferAllocator::instance();\n\tif (mBuffers != nullptr) {\n\t\talloc.Deallocate(mBuffers);\n\t\tmBuffers = nullptr;\n\t}\n\tconst uint32_t nstreams = ASBD::IsInterleaved(format) ? 1 : format.mChannelsPerFrame;\n\tmBuffers = alloc.Allocate(nstreams, nFrames * format.mBytesPerFrame, 0u);\n\tmAllocatedFrames = nFrames;\n\tmAllocatedStreams = nstreams;\n\tmPtrState = EPtrState::Invalid;\n}\n\nvoid AUBufferList::Deallocate()\n{\n\tif (mBuffers != nullptr) {\n\t\tBufferAllocator::instance().Deallocate(mBuffers);\n\t\tmBuffers = nullptr;\n\t}\n\n\tmAllocatedFrames = 0;\n\tmAllocatedStreams = 0;\n\tmPtrState = EPtrState::Invalid;\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUBufferAllocator.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUBufferAllocator.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUBuffer.h>\n\nnamespace ausdk {\n\nBufferAllocator& BufferAllocator::instance()\n{\n\t__attribute__((no_destroy)) static BufferAllocator global;\n\treturn global;\n}\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUEffectBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUEffectBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUEffectBase.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <cstddef>\n\n/*\n\tThis class does not deal as well as it should with N-M effects...\n\n\tThe problem areas are (if the channels don't match):\n\t\tProcessInPlace if the channels don't match - there will be problems if InputChan !=\n   OutputChan Bypass - its just passing the buffers through when not processing them\n*/\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n//_____________________________________________________________________________\n//\nAUEffectBase::AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace)\n\t: AUBase(audioUnit, 1, 1), // 1 in bus, 1 out bus\n\t  mProcessesInPlace(inProcessesInPlace)\n#if TARGET_OS_IPHONE\n\t  ,\n\t  mOnlyOneKernel(false)\n#endif\n{\n}\n\n//_____________________________________________________________________________\n//\nvoid AUEffectBase::Cleanup()\n{\n\tmKernelList.clear();\n\tmMainOutput = nullptr;\n\tmMainInput = nullptr;\n}\n\n\n//_____________________________________________________________________________\n//\nOSStatus AUEffectBase::Initialize()\n{\n\tAUInputElement& in0 = GetInput0();\n\tAUOutputElement& out0 = GetOutput0();\n\n\t// get our current numChannels for input and output\n\tconst auto auNumInputs = static_cast<SInt16>(in0.GetStreamFormat().mChannelsPerFrame);\n\tconst auto auNumOutputs = static_cast<SInt16>(out0.GetStreamFormat().mChannelsPerFrame);\n\n\t// does the unit publish specific information about channel configurations?\n\tconst AUChannelInfo* auChannelConfigs = nullptr;\n\tconst UInt32 numIOconfigs = SupportedNumChannels(&auChannelConfigs);\n\n\tif ((numIOconfigs > 0) && (auChannelConfigs != nullptr)) {\n\t\tbool foundMatch = false;\n\t\tfor (UInt32 i = 0; (i < numIOconfigs) && !foundMatch; ++i) {\n\t\t\tconst SInt16 configNumInputs = auChannelConfigs[i].inChannels;   // NOLINT\n\t\t\tconst SInt16 configNumOutputs = auChannelConfigs[i].outChannels; // NOLINT\n\t\t\tif ((configNumInputs < 0) && (configNumOutputs < 0)) {\n\t\t\t\t// unit accepts any number of channels on input and output\n\t\t\t\tif (((configNumInputs == -1) && (configNumOutputs == -2)) ||\n\t\t\t\t\t((configNumInputs == -2) &&\n\t\t\t\t\t\t(configNumOutputs == -1))) { // NOLINT repeated branch below\n\t\t\t\t\tfoundMatch = true;\n\t\t\t\t\t// unit accepts any number of channels on input and output IFF they are the same\n\t\t\t\t\t// number on both scopes\n\t\t\t\t} else if (((configNumInputs == -1) && (configNumOutputs == -1)) &&\n\t\t\t\t\t\t   (auNumInputs == auNumOutputs)) {\n\t\t\t\t\tfoundMatch = true;\n\t\t\t\t\t// unit has specified a particular number of channels on both scopes\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// the -1 case on either scope is saying that the unit doesn't care about the\n\t\t\t\t// number of channels on that scope\n\t\t\t\tconst bool inputMatch = (auNumInputs == configNumInputs) || (configNumInputs == -1);\n\t\t\t\tconst bool outputMatch =\n\t\t\t\t\t(auNumOutputs == configNumOutputs) || (configNumOutputs == -1);\n\t\t\t\tif (inputMatch && outputMatch) {\n\t\t\t\t\tfoundMatch = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tAUSDK_Require(foundMatch, kAudioUnitErr_FormatNotSupported);\n\t} else {\n\t\t// there is no specifically published channel info\n\t\t// so for those kinds of effects, the assumption is that the channels (whatever their\n\t\t// number) should match on both scopes\n\t\tAUSDK_Require(\n\t\t\t(auNumOutputs == auNumInputs) && (auNumOutputs != 0), kAudioUnitErr_FormatNotSupported);\n\t}\n\tMaintainKernels();\n\n\tmMainOutput = &out0;\n\tmMainInput = &in0;\n\n\tconst AudioStreamBasicDescription format = out0.GetStreamFormat();\n\tmBytesPerFrame = format.mBytesPerFrame;\n\n\treturn noErr;\n}\n\nOSStatus AUEffectBase::Reset(AudioUnitScope inScope, AudioUnitElement inElement)\n{\n\tfor (auto& kernel : mKernelList) {\n\t\tif (kernel) {\n\t\t\tkernel->Reset();\n\t\t}\n\t}\n\n\treturn AUBase::Reset(inScope, inElement);\n}\n\nOSStatus AUEffectBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable)\n{\n\tif (inScope == kAudioUnitScope_Global) {\n\t\tswitch (inID) {\n\t\tcase kAudioUnitProperty_BypassEffect:\n\t\tcase kAudioUnitProperty_InPlaceProcessing:\n\t\t\toutWritable = true;\n\t\t\toutDataSize = sizeof(UInt32);\n\t\t\treturn noErr;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);\n}\n\n\nOSStatus AUEffectBase::GetProperty(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)\n{\n\tif (inScope == kAudioUnitScope_Global) {\n\t\tswitch (inID) {\n\t\tcase kAudioUnitProperty_BypassEffect:\n\t\t\tSerialize<UInt32>(IsBypassEffect() ? 1 : 0, outData);\n\t\t\treturn noErr;\n\t\tcase kAudioUnitProperty_InPlaceProcessing:\n\t\t\tSerialize<UInt32>(mProcessesInPlace ? 1 : 0, outData);\n\t\t\treturn noErr;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn AUBase::GetProperty(inID, inScope, inElement, outData);\n}\n\n\nOSStatus AUEffectBase::SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n{\n\tif (inScope == kAudioUnitScope_Global) {\n\t\tswitch (inID) {\n\t\tcase kAudioUnitProperty_BypassEffect: {\n\t\t\tAUSDK_Require(inDataSize >= sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);\n\n\t\t\tconst bool tempNewSetting = Deserialize<UInt32>(inData) != 0;\n\t\t\t// we're changing the state of bypass\n\t\t\tif (tempNewSetting != IsBypassEffect()) {\n\t\t\t\tif (!tempNewSetting && IsBypassEffect() &&\n\t\t\t\t\tIsInitialized()) { // turning bypass off and we're initialized\n\t\t\t\t\tReset(kAudioUnitScope_Global, 0);\n\t\t\t\t}\n\t\t\t\tSetBypassEffect(tempNewSetting);\n\t\t\t}\n\t\t\treturn noErr;\n\t\t}\n\t\tcase kAudioUnitProperty_InPlaceProcessing:\n            AUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);\n\t\t\tmProcessesInPlace = Deserialize<UInt32>(inData) != 0;\n\t\t\treturn noErr;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize);\n}\n\n\nvoid AUEffectBase::MaintainKernels()\n{\n#if TARGET_OS_IPHONE\n\tconst UInt32 nKernels = mOnlyOneKernel ? 1 : GetNumberOfChannels();\n#else\n\tconst UInt32 nKernels = GetNumberOfChannels();\n#endif\n\n\tif (mKernelList.size() < nKernels) {\n\t\tmKernelList.reserve(nKernels);\n\t\tfor (auto i = static_cast<UInt32>(mKernelList.size()); i < nKernels; ++i) {\n\t\t\tmKernelList.push_back(NewKernel());\n\t\t}\n\t} else {\n\t\twhile (mKernelList.size() > nKernels) {\n\t\t\tmKernelList.pop_back();\n\t\t}\n\t}\n\n\tfor (UInt32 i = 0; i < nKernels; i++) {\n\t\tif (mKernelList[i]) {\n\t\t\tmKernelList[i]->SetChannelNum(i);\n\t\t}\n\t}\n}\n\nbool AUEffectBase::StreamFormatWritable(AudioUnitScope /*scope*/, AudioUnitElement /*element*/)\n{\n\treturn !IsInitialized();\n}\n\nOSStatus AUEffectBase::ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,\n\tconst AudioStreamBasicDescription& inPrevFormat, const AudioStreamBasicDescription& inNewFormat)\n{\n\tAUSDK_Require_noerr(AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat));\n\n\t// for the moment this only dependency we know about\n\t// where a parameter's range may change is with the sample rate\n\t// and effects are only publishing parameters in the global scope!\n\tif (GetParamHasSampleRateDependency() && inPrevFormat.mSampleRate != inNewFormat.mSampleRate) {\n\t\tPropertyChanged(kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0);\n\t}\n\n\treturn noErr;\n}\n\n\n// ____________________________________________________________________________\n//\n//\tThis method is called (potentially repeatedly) by ProcessForScheduledParams()\n//\tin order to perform the actual DSP required for this portion of the entire buffer\n//\tbeing processed.  The entire buffer can be divided up into smaller \"slices\"\n//\taccording to the timestamps on the scheduled parameters...\n//\nOSStatus AUEffectBase::ProcessScheduledSlice(void* inUserData, UInt32 /*inStartFrameInBuffer*/,\n\tUInt32 inSliceFramesToProcess, UInt32 /*inTotalBufferFrames*/) AUSDK_RTSAFE\n{\n\tconst ScheduledProcessParams& sliceParams = *static_cast<ScheduledProcessParams*>(inUserData);\n\n\tAudioUnitRenderActionFlags& actionFlags = *sliceParams.actionFlags;\n\tAudioBufferList& inputBufferList = *sliceParams.inputBufferList;\n\tAudioBufferList& outputBufferList = *sliceParams.outputBufferList;\n\n\tUInt32 channelSize = inSliceFramesToProcess * mBytesPerFrame;\n\t// fix the size of the buffer we're operating on before we render this slice of time\n\tfor (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) {\n\t\tinputBufferList.mBuffers[i].mDataByteSize =                    // NOLINT\n\t\t\tinputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT\n\t}\n\n\tfor (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) {\n\t\toutputBufferList.mBuffers[i].mDataByteSize =                    // NOLINT\n\t\t\toutputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT\n\t}\n\t// process the buffer\n\tconst OSStatus result =\n\t\tProcessBufferLists(actionFlags, inputBufferList, outputBufferList, inSliceFramesToProcess);\n\n\t// we just partially processed the buffers, so increment the data pointers to the next part of\n\t// the buffer to process\n\tfor (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) {\n\t\tinputBufferList.mBuffers[i].mData =                              // NOLINT\n\t\t\tstatic_cast<std::byte*>(inputBufferList.mBuffers[i].mData) + // NOLINT\n\t\t\tinputBufferList.mBuffers[i].mNumberChannels * channelSize;   // NOLINT\n\t}\n\n\tfor (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) {\n\t\toutputBufferList.mBuffers[i].mData =                              // NOLINT\n\t\t\tstatic_cast<std::byte*>(outputBufferList.mBuffers[i].mData) + // NOLINT\n\t\t\toutputBufferList.mBuffers[i].mNumberChannels * channelSize;   // NOLINT\n\t}\n\n\treturn result;\n}\n\n// ____________________________________________________________________________\n//\n\nOSStatus AUEffectBase::Render(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, UInt32 nFrames) AUSDK_RTSAFE\n{\n\tAUSDK_Require(mMainInput->IsActive(), kAudioUnitErr_NoConnection);\n\n\tAUSDK_Require_noerr(\n\t\tmMainInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames));\n\n\tAudioBufferList& inputBufferList =\n\t\tAUSDK_UnwrapOrReturnError(mMainInput->GetBufferListOrError());\n\tAudioBufferList& outputBufferList =\n\t\tAUSDK_UnwrapOrReturnError(mMainOutput->GetBufferListOrError());\n\n\tif (ProcessesInPlace() && mMainOutput->WillAllocateBuffer()) {\n\t\tconst auto setResult = mMainOutput->SetBufferListOrError(inputBufferList);\n\t\tif (!setResult) {\n\t\t\treturn setResult.error();\n\t\t}\n\t}\n\n\tOSStatus result = noErr;\n\n\tif (ShouldBypassEffect()) {\n\t\t// leave silence bit alone\n\n\t\tif (!ProcessesInPlace()) {\n\t\t\tauto val = mMainInput->CopyBufferContentsToOrError(outputBufferList);\n\t\t\tif (!val) {\n\t\t\t\tresult = val.error();\n\t\t\t}\n\t\t}\n\t} else {\n\t\tauto& paramEventList = GetParamEventList();\n\n\t\tif (paramEventList.empty()) {\n\t\t\t// this will read/write silence bit\n\t\t\tresult = ProcessBufferLists(ioActionFlags, inputBufferList, outputBufferList, nFrames);\n\t\t} else {\n\t\t\t// deal with scheduled parameters...\n\n\t\t\tScheduledProcessParams processParams{ .actionFlags = &ioActionFlags,\n\t\t\t\t.inputBufferList = &inputBufferList,\n\t\t\t\t.outputBufferList = &outputBufferList };\n\n\t\t\t// divide up the buffer into slices according to scheduled params then\n\t\t\t// do the DSP for each slice (ProcessScheduledSlice() called for each slice)\n\t\t\tresult = ProcessForScheduledParams(paramEventList, nFrames, &processParams);\n\n\t\t\t// fixup the buffer pointers to how they were before we started\n\t\t\tconst UInt32 channelSize = nFrames * mBytesPerFrame;\n\t\t\tfor (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) {\n\t\t\t\tconst UInt32 size =\n\t\t\t\t\tinputBufferList.mBuffers[i].mNumberChannels * channelSize;         // NOLINT\n\t\t\t\tinputBufferList.mBuffers[i].mData =                                    // NOLINT\n\t\t\t\t\tstatic_cast<std::byte*>(inputBufferList.mBuffers[i].mData) - size; // NOLINT\n\t\t\t\tinputBufferList.mBuffers[i].mDataByteSize = size;                      // NOLINT\n\t\t\t}\n\n\t\t\tfor (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) {\n\t\t\t\tconst UInt32 size =\n\t\t\t\t\toutputBufferList.mBuffers[i].mNumberChannels * channelSize;         // NOLINT\n\t\t\t\toutputBufferList.mBuffers[i].mData =                                    // NOLINT\n\t\t\t\t\tstatic_cast<std::byte*>(outputBufferList.mBuffers[i].mData) - size; // NOLINT\n\t\t\t\toutputBufferList.mBuffers[i].mDataByteSize = size;                      // NOLINT\n\t\t\t}\n\t\t}\n\t}\n\n\tif (((ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0u) && !ProcessesInPlace()) {\n\t\tAUBufferList::ZeroBuffer(outputBufferList);\n\t}\n\n\treturn result;\n}\n\n\nOSStatus AUEffectBase::ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioBufferList& inBuffer, AudioBufferList& outBuffer,\n\tUInt32 inFramesToProcess) AUSDK_RTSAFE\n{\n\tif (ShouldBypassEffect()) {\n\t\treturn noErr;\n\t}\n\n\tconst bool silentInput = IsInputSilent(ioActionFlags, inFramesToProcess);\n\tioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;\n\n\tfor (UInt32 channel = 0; channel < mKernelList.size(); ++channel) {\n\t\tauto& kernel = mKernelList[channel];\n\n\t\tif (!kernel) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tbool ioSilence = silentInput;\n\t\tconst AudioBuffer* const srcBuffer = &inBuffer.mBuffers[channel];   // NOLINT subscript\n\t\tconst AudioBuffer* const destBuffer = &outBuffer.mBuffers[channel]; // NOLINT subscript\n\n\t\tkernel->Process(static_cast<const Float32*>(srcBuffer->mData),\n\t\t\tstatic_cast<Float32*>(destBuffer->mData), inFramesToProcess, ioSilence);\n\n\t\tif (!ioSilence) {\n\t\t\tioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;\n\t\t}\n\t}\n\n\treturn noErr;\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUInputElement.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUInputElement.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUInputElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\nconstexpr bool HasGoodBufferPointers(const AudioBufferList& abl, UInt32 nBytes) noexcept\n{\n\tconst AudioBuffer* buf = abl.mBuffers;                   // NOLINT\n\tfor (UInt32 i = abl.mNumberBuffers; i > 0; --i, ++buf) { // NOLINT\n\t\tif (buf->mData == nullptr || buf->mDataByteSize < nBytes) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//\tAUInputElement::SetConnection\n//\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nvoid AUInputElement::SetConnection(const AudioUnitConnection& conn)\n{\n\tif (conn.sourceAudioUnit == nullptr) {\n\t\tDisconnect();\n\t\treturn;\n\t}\n\n\tmInputType = EInputType::FromConnection;\n\tmConnection = conn;\n\tAllocateBuffer();\n}\n\nvoid AUInputElement::Disconnect()\n{\n\tmInputType = EInputType::NoInput;\n\tIOBuffer().Deallocate();\n}\n\n\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//\tAUInputElement::SetInputCallback\n//\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nvoid AUInputElement::SetInputCallback(AURenderCallback proc, void* refCon)\n{\n\tif (proc == nullptr) {\n\t\tDisconnect();\n\t} else {\n\t\tmInputType = EInputType::FromCallback;\n\t\tmInputProc = proc;\n\t\tmInputProcRefCon = refCon;\n\t\tAllocateBuffer();\n\t}\n}\n\nOSStatus AUInputElement::SetStreamFormat(const AudioStreamBasicDescription& fmt)\n{\n\tconst OSStatus err = AUIOElement::SetStreamFormat(fmt);\n\tif (err == noErr) {\n\t\tAllocateBuffer();\n\t}\n\treturn err;\n}\n\nOSStatus AUInputElement::PullInput(AudioUnitRenderActionFlags& ioActionFlags,\n\tconst AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames) AUSDK_RTSAFE\n{\n\tAUSDK_Require(IsActive(), kAudioUnitErr_NoConnection);\n\n\tauto& iob = IOBuffer();\n\n\tExpectedPtr<AudioBufferList> pullBuffer =\n\t\t(HasConnection() || !WillAllocateBuffer())\n\t\t\t? iob.PrepareNullBufferOrError(GetStreamFormat(), nFrames)\n\t\t\t: iob.PrepareBufferOrError(GetStreamFormat(), nFrames);\n\tif (!pullBuffer) {\n\t\treturn pullBuffer.error();\n\t}\n\n\treturn PullInputWithBufferList(ioActionFlags, inTimeStamp, inElement, nFrames, *pullBuffer);\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUMIDIBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUMIDIBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUConfig.h>\n\n#if AUSDK_HAVE_MIDI\n\n#include <AudioUnitSDK/AUMIDIBase.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <CoreMIDI/CoreMIDI.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n// MIDI CC data bytes\nconstexpr uint8_t kMIDIController_AllSoundOff = 120u;\nconstexpr uint8_t kMIDIController_ResetAllControllers = 121u;\nconstexpr uint8_t kMIDIController_AllNotesOff = 123u;\n\nOSStatus AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable)\n{\n\t(void)inScope;\n\t(void)inElement;\n\t(void)outDataSize;\n\t(void)outWritable;\n\n\tswitch (inID) { // NOLINT if/else?!\n#if AUSDK_HAVE_XML_NAMES\n\tcase kMusicDeviceProperty_MIDIXMLNames:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\tAUSDK_Require(GetXMLNames(nullptr) == noErr, kAudioUnitErr_InvalidProperty);\n\t\toutDataSize = sizeof(CFURLRef);\n\t\toutWritable = false;\n\t\treturn noErr;\n#endif\n\n#if AUSDK_HAVE_MIDI_MAPPING\n\tcase kAudioUnitProperty_AllParameterMIDIMappings:\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\toutWritable = true;\n\t\toutDataSize = sizeof(AUParameterMIDIMapping) * mMIDIMapper->GetNumberMaps();\n\t\treturn noErr;\n\n\tcase kAudioUnitProperty_HotMapParameterMIDIMapping:\n\tcase kAudioUnitProperty_AddParameterMIDIMapping:\n\tcase kAudioUnitProperty_RemoveParameterMIDIMapping:\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\toutWritable = true;\n\t\toutDataSize = sizeof(AUParameterMIDIMapping);\n\t\treturn noErr;\n#endif\n\n\tdefault:\n\t\treturn kAudioUnitErr_InvalidProperty;\n\t}\n}\n\nOSStatus AUMIDIBase::DelegateGetProperty(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)\n{\n\t(void)inScope;\n\t(void)inElement;\n\t(void)outData;\n\n\tswitch (inID) { // NOLINT if/else?!\n#if AUSDK_HAVE_XML_NAMES\n\tcase kMusicDeviceProperty_MIDIXMLNames: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\tCFURLRef url = nullptr;\n\t\tconst auto result = GetXMLNames(&url);\n\t\tSerialize(url, outData);\n\t\treturn result;\n\t}\n#endif\n\n#if AUSDK_HAVE_MIDI_MAPPING\n\tcase kAudioUnitProperty_AllParameterMIDIMappings: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\tstd::vector<AUParameterMIDIMapping> maps(mMIDIMapper->GetNumberMaps());\n\t\tmMIDIMapper->GetMaps(maps.data());\n\t\tSerialize(std::span(maps), outData);\n\t\treturn noErr;\n\t}\n\n\tcase kAudioUnitProperty_HotMapParameterMIDIMapping: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n\t\tAUParameterMIDIMapping map{};\n\t\tmMIDIMapper->GetHotParameterMap(map);\n\t\tSerialize(map, outData);\n\t\treturn noErr;\n\t}\n#endif\n\n\tdefault:\n\t\treturn kAudioUnitErr_InvalidProperty;\n\t}\n}\n\nOSStatus AUMIDIBase::DelegateSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n{\n\t(void)inScope;\n\t(void)inElement;\n\t(void)inData;\n\t(void)inDataSize;\n\n\tswitch (inID) {\n\n#if AUSDK_HAVE_MIDI_MAPPING\n\tcase kAudioUnitProperty_AddParameterMIDIMapping: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n        AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n        const auto validSize = (inDataSize > 0) && (inDataSize % sizeof(AUParameterMIDIMapping)) == 0;\n        AUSDK_Require(validSize, kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto maps = DeserializeArray<AUParameterMIDIMapping>(inData, inDataSize);\n\t\tmMIDIMapper->AddParameterMapping(\n\t\t\tmaps.data(), static_cast<UInt32>(maps.size()), mAUBaseInstance);\n\t\tmAUBaseInstance.PropertyChanged(\n\t\t\tkAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);\n\t\treturn noErr;\n\t}\n\n\tcase kAudioUnitProperty_RemoveParameterMIDIMapping: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n        const auto validSize = (inDataSize > 0) && (inDataSize % sizeof(AUParameterMIDIMapping)) == 0;\n        AUSDK_Require(validSize, kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto maps = DeserializeArray<AUParameterMIDIMapping>(inData, inDataSize);\n\t\tbool didChange = false;\n\t\tmMIDIMapper->RemoveParameterMapping(\n\t\t\tmaps.data(), static_cast<UInt32>(maps.size()), didChange);\n\t\tif (didChange) {\n\t\t\tmAUBaseInstance.PropertyChanged(\n\t\t\t\tkAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);\n\t\t}\n\t\treturn noErr;\n\t}\n\n\tcase kAudioUnitProperty_HotMapParameterMIDIMapping: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n        AUSDK_Require(inDataSize == sizeof(AUParameterMIDIMapping), kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto map = Deserialize<AUParameterMIDIMapping>(inData);\n\t\tmMIDIMapper->SetHotMapping(map);\n\t\treturn noErr;\n\t}\n\n\tcase kAudioUnitProperty_AllParameterMIDIMappings: {\n\t\tAUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty);\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tAUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement);\n        const auto validSize = (inDataSize > 0) && (inDataSize % sizeof(AUParameterMIDIMapping)) == 0;\n        AUSDK_Require(validSize, kAudioUnitErr_InvalidPropertyValue);\n\t\tconst auto maps = DeserializeArray<AUParameterMIDIMapping>(inData, inDataSize);\n\t\tmMIDIMapper->ReplaceAllMaps(maps.data(), static_cast<UInt32>(maps.size()), mAUBaseInstance);\n\t\treturn noErr;\n\t}\n#endif\n\n\tdefault:\n\t\treturn kAudioUnitErr_InvalidProperty;\n\t}\n}\n\nconstexpr uint8_t MIDIStatusNibbleValue(uint8_t status) noexcept { return (status & 0xF0U) >> 4u; }\n\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//\tAUMIDIBase::HandleMIDIEvent\n//\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOSStatus AUMIDIBase::HandleMIDIEvent(\n\tUInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) AUSDK_RTSAFE\n{\n\tAUSDK_Require(mAUBaseInstance.IsInitialized(), kAudioUnitErr_Uninitialized);\n\n#if AUSDK_HAVE_MIDI_MAPPING\n\t// you potentially have a choice to make here - if a param mapping matches, do you still want to\n\t// process the MIDI event or not. The default behaviour is to continue on with the MIDI event.\n\tif (mMIDIMapper) {\n\t\tif (mMIDIMapper->HandleHotMapping(status, channel, data1, mAUBaseInstance)) {\n\t\t\tAUSDK_RT_UNSAFE_BEGIN(\"FIXME: PropertyChanged is unsafe\")\n\t\t\tmAUBaseInstance.PropertyChanged(\n\t\t\t\tkAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0);\n\t\t\tAUSDK_RT_UNSAFE_END\n\t\t} else {\n\t\t\tmMIDIMapper->FindParameterMapEventMatch(\n\t\t\t\tstatus, channel, data1, data2, inStartFrame, mAUBaseInstance);\n\t\t}\n\t}\n#endif\n\tswitch (MIDIStatusNibbleValue(status)) {\n\tcase kMIDICVStatusNoteOn:\n\t\tif (data2 != 0u) {\n\t\t\treturn HandleNoteOn(channel, data1, data2, inStartFrame);\n\t\t} else {\n\t\t\t// zero velocity translates to note off\n\t\t\treturn HandleNoteOff(channel, data1, data2, inStartFrame);\n\t\t}\n\n\tcase kMIDICVStatusNoteOff:\n\t\treturn HandleNoteOff(channel, data1, data2, inStartFrame);\n\n\tdefault:\n\t\treturn HandleNonNoteEvent(status, channel, data1, data2, inStartFrame);\n\t}\n}\n\nOSStatus AUMIDIBase::HandleNonNoteEvent(\n\tUInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) AUSDK_RTSAFE\n{\n\tswitch (MIDIStatusNibbleValue(status)) {\n\tcase kMIDICVStatusPitchBend:\n\t\treturn HandlePitchWheel(channel, data1, data2, inStartFrame);\n\n\tcase kMIDICVStatusProgramChange:\n\t\treturn HandleProgramChange(channel, data1);\n\n\tcase kMIDICVStatusChannelPressure:\n\t\treturn HandleChannelPressure(channel, data1, inStartFrame);\n\n\tcase kMIDICVStatusControlChange: {\n\t\tswitch (data1) {\n\t\tcase kMIDIController_AllNotesOff:\n\t\t\treturn HandleAllNotesOff(channel);\n\n\t\tcase kMIDIController_ResetAllControllers:\n\t\t\treturn HandleResetAllControllers(channel);\n\n\t\tcase kMIDIController_AllSoundOff:\n\t\t\treturn HandleAllSoundOff(channel);\n\n\t\tdefault:\n\t\t\treturn HandleControlChange(channel, data1, data2, inStartFrame);\n\t\t}\n\t}\n\n\tcase kMIDICVStatusPolyPressure:\n\t\treturn HandlePolyPressure(channel, data1, data2, inStartFrame);\n\n\tdefault:\n\t\treturn noErr;\n\t}\n}\n\nOSStatus AUMIDIBase::SysEx(const UInt8* inData, UInt32 inLength) AUSDK_RTSAFE\n{\n\tAUSDK_Require(mAUBaseInstance.IsInitialized(), kAudioUnitErr_Uninitialized);\n\n\treturn HandleSysEx(inData, inLength);\n}\n\n} // namespace ausdk\n\nAUSDK_END_NO_RT_WARNINGS\n\n#endif // AUSDK_HAVE_MIDI\n"
  },
  {
    "path": "src/AudioUnitSDK/AUMIDIEffectBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUMIDIEffectBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUMIDIEffectBase.h>\n\nnamespace ausdk {\n\nAUMIDIEffectBase::AUMIDIEffectBase(AudioComponentInstance inInstance, bool inProcessesInPlace)\n\t: AUEffectBase(inInstance, inProcessesInPlace), AUMIDIBase(*static_cast<AUBase*>(this))\n{\n}\n\nOSStatus AUMIDIEffectBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable)\n{\n\tOSStatus result =\n\t\tAUEffectBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);\n\n\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\tresult =\n\t\t\tAUMIDIBase::DelegateGetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);\n\t}\n\n\treturn result;\n}\n\nOSStatus AUMIDIEffectBase::GetProperty(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)\n{\n\tOSStatus result = AUEffectBase::GetProperty(inID, inScope, inElement, outData);\n\n\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\tresult = AUMIDIBase::DelegateGetProperty(inID, inScope, inElement, outData);\n\t}\n\n\treturn result;\n}\n\nOSStatus AUMIDIEffectBase::SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n{\n\n\tOSStatus result = AUEffectBase::SetProperty(inID, inScope, inElement, inData, inDataSize);\n\n\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\tresult = AUMIDIBase::DelegateSetProperty(inID, inScope, inElement, inData, inDataSize);\n\t}\n\n\treturn result;\n}\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUOutputElement.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUOutputElement.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUOutputElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\nnamespace ausdk {\n\nAUOutputElement::AUOutputElement(AUBase& audioUnit) : AUIOElement(audioUnit) { AllocateBuffer(); }\n\nAUOutputElement::AUOutputElement(AUBase& audioUnit, const AudioStreamBasicDescription& format)\n\t: AUIOElement{ audioUnit, format }\n{\n\tAllocateBuffer();\n}\n\nOSStatus AUOutputElement::SetStreamFormat(const AudioStreamBasicDescription& desc)\n{\n\tAUSDK_Require_noerr(AUIOElement::SetStreamFormat(desc)); // inherited\n\tAllocateBuffer();\n\treturn noErr;\n}\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUPlugInDispatch.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUPlugInDispatch.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n// clang-format off\n#include <AudioUnitSDK/AUConfig.h> // must come first\n// clang-format on\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUPlugInDispatch.h>\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/ComponentBase.h>\n\n#if AUSDK_HAVE_MUSIC_DEVICE\n#include <AudioToolbox/MusicDevice.h>\n#endif\n\n#if AUSDK_HAVE_IO_UNITS\n#include <AudioToolbox/AudioOutputUnit.h>\n#endif\n\n#include <cmath>\n#include <cstddef>\n#include <cstring>\n\n#define AUSDK_HAVE_MUSIC_DEVICE_PREPARE_RELEASE (AUSDK_HAVE_MUSIC_DEVICE && TARGET_OS_OSX) // NOLINT\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n// ------------------------------------------------------------------------------------------------\nstatic auto AUInstance(void* self)\n{\n\treturn reinterpret_cast<AUBase*>( // NOLINT reinterpret_cast\n\t\t&(static_cast<AudioComponentPlugInInstance*>(self)->mInstanceStorage));\n}\n\n// ------------------------------------------------------------------------------------------------\nclass AUInstanceGuard {\npublic:\n\texplicit AUInstanceGuard(void* self) : mGuard(AUInstance(self)->GetMutex()) {}\n\nprivate:\n\tconst AUEntryGuard mGuard;\n};\n\n// ------------------------------------------------------------------------------------------------\nstatic bool IsValidParameterValue(AudioUnitParameterValue value) { return std::isfinite(value); }\n\nstatic bool AreValidParameterEvents(const AudioUnitParameterEvent* events, UInt32 numEvents)\n{\n\tif (events == nullptr) {\n\t\treturn true;\n\t}\n\n\tfor (UInt32 i = 0; i < numEvents; ++i) {\n\t\tconst auto& event = events[i]; // NOLINT\n\t\tswitch (event.eventType) {\n\t\tcase kParameterEvent_Immediate: {\n\t\t\tif (!IsValidParameterValue(event.eventValues.immediate.value)) { // NOLINT\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase kParameterEvent_Ramped: {\n\t\t\tif (!IsValidParameterValue(event.eventValues.ramp.startValue) || // NOLINT\n\t\t\t\t!IsValidParameterValue(event.eventValues.ramp.endValue)) {   // NOLINT\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n// ------------------------------------------------------------------------------------------------\nstatic OSStatus AUMethodInitialize(void* self)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->DoInitialize();\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodUninitialize(void* self)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tAUInstance(self)->DoCleanup();\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodGetPropertyInfo(void* self, AudioUnitPropertyID prop, AudioUnitScope scope,\n\tAudioUnitElement elem, UInt32* outDataSize, Boolean* outWritable)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tUInt32 dataSize = 0; // 13517289 GetPropetyInfo was returning an uninitialized value when\n\t\t\t\t\t\t\t // there is an error. This is a problem for auval.\n\t\tbool writable = false;\n\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->DispatchGetPropertyInfo(prop, scope, elem, dataSize, writable);\n\t\tif (outDataSize != nullptr) {\n\t\t\t*outDataSize = dataSize;\n\t\t}\n\t\tif (outWritable != nullptr) {\n\t\t\t*outWritable = static_cast<Boolean>(writable);\n\t\t}\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodGetProperty(void* self, AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, void* outData, UInt32* ioDataSize)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tbool writable = false;\n\n\t\tconst AUInstanceGuard guard(self);\n\t\tif (ioDataSize == nullptr) {\n\t\t\tAUSDK_LogError(\"AudioUnitGetProperty: null size pointer\");\n\t\t\treturn kAudio_ParamError;\n\t\t}\n\t\tif (outData == nullptr) {\n\t\t\tUInt32 dataSize = 0;\n\n\t\t\tresult = AUInstance(self)->DispatchGetPropertyInfo(\n\t\t\t\tinID, inScope, inElement, dataSize, writable);\n\t\t\t*ioDataSize = dataSize;\n\t\t\treturn result;\n\t\t}\n\n\t\tconst auto clientBufferSize = *ioDataSize;\n\t\tif (clientBufferSize == 0) {\n\t\t\tAUSDK_LogError(\"AudioUnitGetProperty: *ioDataSize == 0 on entry\");\n\t\t\treturn kAudio_ParamError;\n\t\t}\n\n\t\tUInt32 actualPropertySize = 0;\n\t\tAUSDK_Require_noerr(AUInstance(self)->DispatchGetPropertyInfo(\n\t\t\tinID, inScope, inElement, actualPropertySize, writable));\n\n\t\tstd::vector<std::byte> tempBuffer;\n\t\tvoid* destBuffer = nullptr;\n\t\tif (clientBufferSize < actualPropertySize) {\n\t\t\ttempBuffer.resize(actualPropertySize);\n\t\t\tdestBuffer = tempBuffer.data();\n\t\t} else {\n\t\t\tdestBuffer = outData;\n\t\t}\n\n\t\tresult = AUInstance(self)->DispatchGetProperty(inID, inScope, inElement, destBuffer);\n\n\t\tif (result == noErr) {\n\t\t\tif (clientBufferSize < actualPropertySize && !tempBuffer.empty()) {\n\t\t\t\tmemcpy(outData, tempBuffer.data(), clientBufferSize);\n\t\t\t\t// ioDataSize remains correct, the number of bytes we wrote\n\t\t\t} else {\n\t\t\t\t*ioDataSize = actualPropertySize;\n\t\t\t}\n\t\t} else {\n\t\t\t*ioDataSize = 0;\n\t\t}\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodSetProperty(void* self, AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tif ((inData != nullptr) && (inDataSize != 0u)) {\n\t\t\tresult =\n\t\t\t\tAUInstance(self)->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize);\n\t\t} else {\n\t\t\tif (inData == nullptr && inDataSize == 0) {\n\t\t\t\tresult = AUInstance(self)->DispatchRemovePropertyValue(inID, inScope, inElement);\n\t\t\t} else {\n\t\t\t\tif (inData == nullptr) {\n\t\t\t\t\tAUSDK_LogError(\"AudioUnitSetProperty: inData == NULL\");\n\t\t\t\t\treturn kAudio_ParamError;\n\t\t\t\t}\n\n\t\t\t\tif (inDataSize == 0) {\n\t\t\t\t\tAUSDK_LogError(\"AudioUnitSetProperty: inDataSize == 0\");\n\t\t\t\t\treturn kAudio_ParamError;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodAddPropertyListener(\n\tvoid* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* userData)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->AddPropertyListener(prop, proc, userData);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodRemovePropertyListener(\n\tvoid* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->RemovePropertyListener(prop, proc, nullptr, false);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodRemovePropertyListenerWithUserData(\n\tvoid* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* userData)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->RemovePropertyListener(prop, proc, userData, true);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodAddRenderNotify(void* self, AURenderCallback proc, void* userData)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->SetRenderNotification(proc, userData);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodRemoveRenderNotify(void* self, AURenderCallback proc, void* userData)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->RemoveRenderNotification(proc, userData);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodGetParameter(void* self, AudioUnitParameterID param, AudioUnitScope scope,\n\tAudioUnitElement elem, AudioUnitParameterValue* value)\n{\n\tOSStatus result = noErr;\n\ttry {\n        // this is a (potentially) realtime method; no lock\n\t\tresult = (value == nullptr ? kAudio_ParamError\n\t\t\t\t\t\t\t\t   : AUInstance(self)->GetParameter(param, scope, elem, *value));\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodSetParameter(void* self, AudioUnitParameterID param, AudioUnitScope scope,\n\tAudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset)\n{\n\tAUSDK_Require(IsValidParameterValue(value), kAudioUnitErr_InvalidParameterValue);\n\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a (potentially) realtime method; no lock\n\t\tresult = AUInstance(self)->SetParameter(param, scope, elem, value, bufferOffset);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodScheduleParameters(\n\tvoid* self, const AudioUnitParameterEvent* events, UInt32 numEvents)\n{\n\tAUSDK_Require(AreValidParameterEvents(events, numEvents), kAudioUnitErr_InvalidParameterValue);\n\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a (potentially) realtime method; no lock\n\t\tresult = AUInstance(self)->ScheduleParameter(events, numEvents);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\n// try/catch unneeded because DoRender is noexcept.\nstatic OSStatus AUMethodRender(void* self, AudioUnitRenderActionFlags* ioActionFlags,\n\tconst AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames,\n\tAudioBufferList* ioData) noexcept AUSDK_RTSAFE\n{\n\tOSStatus result = noErr;\n\n\t// this is a processing method; no lock\n\tAudioUnitRenderActionFlags tempFlags{};\n\n\tif (inTimeStamp == nullptr || ioData == nullptr) {\n\t\tresult = kAudio_ParamError;\n\t} else {\n\t\tif (ioActionFlags == nullptr) {\n\t\t\ttempFlags = 0;\n\t\t\tioActionFlags = &tempFlags;\n\t\t}\n\t\tresult = AUInstance(self)->DoRender(\n\t\t\t*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData);\n\t}\n\n\treturn result;\n}\n\n// try/catch needed here because ComplexRender is virtual and can't be retroactively noexcept.\nstatic OSStatus AUMethodComplexRender(void* self, AudioUnitRenderActionFlags* ioActionFlags,\n\tconst AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberOfPackets,\n\tUInt32* outNumberOfPackets, AudioStreamPacketDescription* outPacketDescriptions,\n\tAudioBufferList* ioData, void* outMetadata, UInt32* outMetadataByteSize) noexcept AUSDK_RTSAFE\n{\n\tOSStatus result = noErr;\n\n\ttry {\n\t\t// this is a processing method; no lock\n\t\tAudioUnitRenderActionFlags tempFlags{};\n\n\t\tif (inTimeStamp == nullptr || ioData == nullptr) {\n\t\t\tresult = kAudio_ParamError;\n\t\t} else {\n\t\t\tif (ioActionFlags == nullptr) {\n\t\t\t\ttempFlags = 0;\n\t\t\t\tioActionFlags = &tempFlags;\n\t\t\t}\n\t\t\tresult = AUInstance(self)->ComplexRender(*ioActionFlags, *inTimeStamp,\n\t\t\t\tinOutputBusNumber, inNumberOfPackets, outNumberOfPackets, outPacketDescriptions,\n\t\t\t\t*ioData, outMetadata, outMetadataByteSize);\n\t\t}\n\t}\n\tAUSDK_RT_UNSAFE(AUSDK_Catch(result))\n\n\treturn result;\n}\n\nstatic OSStatus AUMethodReset(void* self, AudioUnitScope scope, AudioUnitElement elem)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->DoReset(scope, elem);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\n// try/catch unneeded because DoProcess is noexcept.\nstatic OSStatus AUMethodProcess(void* self, AudioUnitRenderActionFlags* ioActionFlags,\n\tconst AudioTimeStamp* inTimeStamp, UInt32 inNumberFrames,\n\tAudioBufferList* ioData) noexcept AUSDK_RTSAFE\n{\n\tOSStatus result = noErr;\n\n\t// this is a processing method; no lock\n\tbool doParamCheck = true;\n\n\tAudioUnitRenderActionFlags tempFlags{};\n\n\tif (ioActionFlags == nullptr) {\n\t\ttempFlags = 0;\n\t\tioActionFlags = &tempFlags;\n\t} else {\n\t\tif ((*ioActionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) != 0u) {\n\t\t\tdoParamCheck = false;\n\t\t}\n\t}\n\n\tif (doParamCheck && (inTimeStamp == nullptr || ioData == nullptr)) {\n\t\tresult = kAudio_ParamError;\n\t} else {\n\t\tresult = AUInstance(self)->DoProcess(*ioActionFlags, *inTimeStamp, inNumberFrames, *ioData);\n\t}\n\n\treturn result;\n}\n\n// try/catch unneeded because DoProcessMultiple is noexcept.\nstatic OSStatus AUMethodProcessMultiple(void* self, AudioUnitRenderActionFlags* ioActionFlags,\n\tconst AudioTimeStamp* inTimeStamp, UInt32 inNumberFrames, UInt32 inNumberInputBufferLists,\n\tconst AudioBufferList** inInputBufferLists, UInt32 inNumberOutputBufferLists,\n\tAudioBufferList** ioOutputBufferLists) noexcept AUSDK_RTSAFE\n{\n\tOSStatus result = noErr;\n\n\t// this is a processing method; no lock\n\tbool doParamCheck = true;\n\n\tAudioUnitRenderActionFlags tempFlags{};\n\n\tif (ioActionFlags == nullptr) {\n\t\ttempFlags = 0;\n\t\tioActionFlags = &tempFlags;\n\t} else {\n\t\tif ((*ioActionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) != 0u) {\n\t\t\tdoParamCheck = false;\n\t\t}\n\t}\n\n\tif (doParamCheck && (inTimeStamp == nullptr || inInputBufferLists == nullptr ||\n\t\t\t\t\t\t\tioOutputBufferLists == nullptr)) {\n\t\tresult = kAudio_ParamError;\n\t} else {\n\t\tresult = AUInstance(self)->DoProcessMultiple(*ioActionFlags, *inTimeStamp, inNumberFrames,\n\t\t\tinNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists,\n\t\t\tioOutputBufferLists);\n\t}\n\n\treturn result;\n}\n// ------------------------------------------------------------------------------------------------\n\n#if AUSDK_HAVE_MUSIC_DEVICE\nstatic OSStatus AUMethodStart(void* self)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->Start();\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodStop(void* self)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst AUInstanceGuard guard(self);\n\t\tresult = AUInstance(self)->Stop();\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n\n// ------------------------------------------------------------------------------------------------\n\n#if AUSDK_HAVE_MIDI\n// I don't know what I'm doing here; conflicts with the multiple inheritence in MusicDeviceBase.\nstatic OSStatus AUMethodMIDIEvent(\n\tvoid* self, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tresult = AUInstance(self)->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodSysEx(void* self, const UInt8* inData, UInt32 inLength)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tresult = AUInstance(self)->SysEx(inData, inLength);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n#endif // AUSDK_HAVE_MIDI\n\n#if AUSDK_HAVE_MIDI2\nstatic OSStatus AUMethodMIDIEventList(\n\tvoid* self, UInt32 inOffsetSampleFrame, const struct MIDIEventList* eventList)\n{\n\tif (eventList == nullptr) {\n\t\treturn kAudio_ParamError;\n\t}\n\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\n\t\t// Note that a MIDIEventList is variably-sized and can be backed by less memory than\n\t\t// required, so it is Undefined Behavior to form a reference to it; we must only use\n\t\t// pointers.\n\t\tresult = AUInstance(self)->MIDIEventList(inOffsetSampleFrame, eventList);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n#endif\n\n#if AUSDK_HAVE_MUSIC_DEVICE\nstatic OSStatus AUMethodStartNote(void* self, MusicDeviceInstrumentID inInstrument,\n\tMusicDeviceGroupID inGroupID, NoteInstanceID* outNoteInstanceID, UInt32 inOffsetSampleFrame,\n\tconst MusicDeviceNoteParams* inParams)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tif (inParams == nullptr) {\n\t\t\tresult = kAudio_ParamError;\n\t\t} else {\n\t\t\tresult = AUInstance(self)->StartNote(\n\t\t\t\tinInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);\n\t\t}\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodStopNote(void* self, MusicDeviceGroupID inGroupID,\n\tNoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tresult = AUInstance(self)->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n\n#if AUSDK_HAVE_MUSIC_DEVICE_PREPARE_RELEASE\nstatic OSStatus AUMethodPrepareInstrument(void* self, MusicDeviceInstrumentID inInstrument)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tresult = AUInstance(self)->PrepareInstrument(inInstrument); // NOLINT static via instance\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nstatic OSStatus AUMethodReleaseInstrument(void* self, MusicDeviceInstrumentID inInstrument)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\t// this is a potential render-time method; no lock\n\t\tresult = AUInstance(self)->ReleaseInstrument(inInstrument); // NOLINT static via instance\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n#endif // AUSDK_HAVE_MUSIC_DEVICE_PREPARE_RELEASE\n\n\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n#pragma mark -\n#pragma mark Lookup Methods\n\nAudioComponentMethod AUBaseLookup::Lookup(SInt16 selector)\n{\n\tswitch (selector) {\n\tcase kAudioUnitInitializeSelect:\n\t\treturn (AudioComponentMethod)AUMethodInitialize; // NOLINT cast\n\tcase kAudioUnitUninitializeSelect:\n\t\treturn (AudioComponentMethod)AUMethodUninitialize; // NOLINT cast\n\tcase kAudioUnitGetPropertyInfoSelect:\n\t\treturn (AudioComponentMethod)AUMethodGetPropertyInfo; // NOLINT cast\n\tcase kAudioUnitGetPropertySelect:\n\t\treturn (AudioComponentMethod)AUMethodGetProperty; // NOLINT cast\n\tcase kAudioUnitSetPropertySelect:\n\t\treturn (AudioComponentMethod)AUMethodSetProperty; // NOLINT cast\n\tcase kAudioUnitAddPropertyListenerSelect:\n\t\treturn (AudioComponentMethod)AUMethodAddPropertyListener; // NOLINT cast\n\tcase kAudioUnitRemovePropertyListenerSelect:\n\t\treturn (AudioComponentMethod)AUMethodRemovePropertyListener; // NOLINT cast\n\tcase kAudioUnitRemovePropertyListenerWithUserDataSelect:\n\t\treturn (AudioComponentMethod)AUMethodRemovePropertyListenerWithUserData; // NOLINT cast\n\tcase kAudioUnitAddRenderNotifySelect:\n\t\treturn (AudioComponentMethod)AUMethodAddRenderNotify; // NOLINT cast\n\tcase kAudioUnitRemoveRenderNotifySelect:\n\t\treturn (AudioComponentMethod)AUMethodRemoveRenderNotify; // NOLINT cast\n\tcase kAudioUnitGetParameterSelect:\n\t\treturn (AudioComponentMethod)AUMethodGetParameter; // NOLINT cast\n\tcase kAudioUnitSetParameterSelect:\n\t\treturn (AudioComponentMethod)AUMethodSetParameter; // NOLINT cast\n\tcase kAudioUnitScheduleParametersSelect:\n\t\treturn (AudioComponentMethod)AUMethodScheduleParameters; // NOLINT cast\n\tcase kAudioUnitRenderSelect:\n\t\treturn (AudioComponentMethod)AUMethodRender; // NOLINT cast\n\tcase kAudioUnitResetSelect:\n\t\treturn (AudioComponentMethod)AUMethodReset; // NOLINT cast\n\tdefault:\n\t\tbreak;\n\t}\n\treturn nullptr;\n}\n\nAudioComponentMethod AUOutputLookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tswitch (selector) {\n#if AUSDK_HAVE_IO_UNITS\n\tcase kAudioOutputUnitStartSelect:\n\t\treturn (AudioComponentMethod)AUMethodStart; // NOLINT cast\n\tcase kAudioOutputUnitStopSelect:\n\t\treturn (AudioComponentMethod)AUMethodStop; // NOLINT cast\n#endif                                             // AUSDK_HAVE_IO_UNITS\n\tdefault:\n\t\tbreak;\n\t}\n\treturn nullptr;\n}\n\nAudioComponentMethod AUComplexOutputLookup::Lookup(SInt16 selector)\n{\n\tAudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tmethod = AUOutputLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tif (selector == kAudioUnitComplexRenderSelect) {\n\t\treturn (AudioComponentMethod)AUMethodComplexRender; // NOLINT cast\n\t}\n\treturn nullptr;\n}\n\nAudioComponentMethod AUBaseProcessLookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tif (selector == kAudioUnitProcessSelect) {\n\t\treturn (AudioComponentMethod)AUMethodProcess; // NOLINT cast\n\t}\n\n\treturn nullptr;\n}\n\nAudioComponentMethod AUBaseProcessMultipleLookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tif (selector == kAudioUnitProcessMultipleSelect) {\n\t\treturn (AudioComponentMethod)AUMethodProcessMultiple; // NOLINT cast\n\t}\n\n\treturn nullptr;\n}\n\nAudioComponentMethod AUBaseProcessAndMultipleLookup::Lookup(SInt16 selector)\n{\n\tAudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tmethod = AUBaseProcessMultipleLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tmethod = AUBaseProcessLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\treturn nullptr;\n}\n\n#if AUSDK_HAVE_MIDI\ninline AudioComponentMethod MIDI_Lookup(SInt16 selector)\n{\n\tswitch (selector) {\n\tcase kMusicDeviceMIDIEventSelect:\n\t\treturn (AudioComponentMethod)AUMethodMIDIEvent; // NOLINT cast\n\tcase kMusicDeviceSysExSelect:\n\t\treturn (AudioComponentMethod)AUMethodSysEx; // NOLINT cast\n#if AUSDK_HAVE_MIDI2\n\tcase kMusicDeviceMIDIEventListSelect:\n\t\treturn (AudioComponentMethod)AUMethodMIDIEventList; // NOLINT cast\n#endif                                                      // AUSDK_HAVE_MIDI2\n\tdefault:\n\t\tbreak;\n\t}\n\treturn nullptr;\n}\n\nAudioComponentMethod AUMIDILookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\treturn MIDI_Lookup(selector);\n}\n\nAudioComponentMethod AUMIDIProcessLookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseProcessLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\treturn MIDI_Lookup(selector);\n}\n#endif // AUSDK_HAVE_MIDI\n\n#if AUSDK_HAVE_MUSIC_DEVICE\nAudioComponentMethod AUMusicLookup::Lookup(SInt16 selector)\n{\n\tconst AudioComponentMethod method = AUBaseLookup::Lookup(selector);\n\tif (method != nullptr) {\n\t\treturn method;\n\t}\n\n\tswitch (selector) {\n\tcase kMusicDeviceStartNoteSelect:\n\t\treturn (AudioComponentMethod)AUMethodStartNote; // NOLINT cast\n\tcase kMusicDeviceStopNoteSelect:\n\t\treturn (AudioComponentMethod)AUMethodStopNote; // NOLINT cast\n#if AUSDK_HAVE_MUSIC_DEVICE_PREPARE_RELEASE\n\tcase kMusicDevicePrepareInstrumentSelect:\n\t\treturn (AudioComponentMethod)AUMethodPrepareInstrument; // NOLINT cast\n\tcase kMusicDeviceReleaseInstrumentSelect:\n\t\treturn (AudioComponentMethod)AUMethodReleaseInstrument; // NOLINT cast\n#endif // AUSDK_HAVE_MUSIC_DEVICE_PREPARE_RELEASE\n\tdefault:\n\t\tbreak;\n\t}\n#if AUSDK_HAVE_MIDI\n\treturn MIDI_Lookup(selector);\n#else\n\treturn nullptr;\n#endif // AUSDK_HAVE_MIDI\n}\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/AUScopeElement.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/AUScopeElement.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUBase.h>\n#include <AudioUnitSDK/AUScopeElement.h>\n#include <AudioUnitSDK/AUUtility.h>\n\n#include <AudioToolbox/AudioUnitProperties.h>\n\n#include <CoreFoundation/CFByteOrder.h>\n\n#include <algorithm>\n#include <array>\n#include <bit>\n#include <cstring>\n#include <numeric>\n#include <utility>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\n//_____________________________________________________________________________\n//\n//\tBy default, parameterIDs may be arbitrarily spaced, and a flat map\n//  will be used for access.  Calling UseIndexedParameters() will\n//\tinstead use an STL vector for faster indexed access.\n//\tThis assumes the paramIDs are numbered 0.....inNumberOfParameters-1\n//\tCall this before defining/adding any parameters with SetParameter()\n//\nvoid AUElement::UseIndexedParameters(UInt32 inNumberOfParameters)\n{\n\tmIndexedParameters.resize(inNumberOfParameters);\n\tmUseIndexedParameters = true;\n}\n\n//_____________________________________________________________________________\n//\n//\tHelper method.\n//\treturns whether the specified paramID is known to the element\n//\nbool AUElement::HasParameterID(AudioUnitParameterID paramID) const AUSDK_RTSAFE\n{\n\tif (mUseIndexedParameters) {\n\t\treturn paramID < mIndexedParameters.size();\n\t}\n\n\treturn mParameters.find(paramID) != mParameters.end();\n}\n\n//_____________________________________________________________________________\n//\n//\tcaller assumes that this is actually an immediate parameter\n//\nExpected<AudioUnitParameterValue> AUElement::GetParameterOrError(\n\tAudioUnitParameterID paramID) const AUSDK_RTSAFE\n{\n\tif (mUseIndexedParameters) {\n\t\tif (paramID >= mIndexedParameters.size()) {\n\t\t\treturn Unexpected{ kAudioUnitErr_InvalidParameter };\n\t\t}\n\t\treturn mIndexedParameters[paramID].load(std::memory_order_acquire);\n\t}\n\tconst auto i = mParameters.find(paramID);\n\tif (i == mParameters.end()) {\n\t\treturn Unexpected{ kAudioUnitErr_InvalidParameter };\n\t}\n\treturn i->second.load(std::memory_order_acquire);\n}\n\n//_____________________________________________________________________________\n//\nExpected<void> AUElement::SetParameterOrError(AudioUnitParameterID paramID,\n\tAudioUnitParameterValue inValue, bool okWhenInitialized) AUSDK_RTSAFE\n{\n\tif (mUseIndexedParameters) {\n\t\tif (paramID >= mIndexedParameters.size()) {\n\t\t\treturn Unexpected{ kAudioUnitErr_InvalidParameter };\n\t\t}\n\t\tmIndexedParameters[paramID].store(inValue, std::memory_order_release);\n\t} else {\n\t\tconst auto i = mParameters.find(paramID);\n\n\t\tif (i == mParameters.end()) {\n\t\t\tif (mAudioUnit.IsInitialized() && !okWhenInitialized) {\n\t\t\t\t// The AU should not be creating new parameters once initialized.\n\t\t\t\t// If a client tries to set an undefined parameter, we could throw as follows,\n\t\t\t\t// but this might cause a regression. So it is better to just fail silently.\n\t\t\t\t// Throw(kAudioUnitErr_InvalidParameter);\n\t\t\t\tAUSDK_LogError_RT(\n\t\t\t\t\t\"Warning: %s SetParameter for undefined param ID %u while initialized. \"\n\t\t\t\t\t\"Ignoring.\",\n\t\t\t\t\tmAudioUnit.GetLoggingString(), static_cast<unsigned>(paramID));\n\t\t\t\treturn Unexpected{ kAudioUnitErr_InvalidParameter };\n\t\t\t} else {\n\t\t\t\t// create new entry in map for the paramID (only happens first time)\n\t\t\t\tAUSDK_RT_UNSAFE_BEGIN(\"only the first time\")\n\t\t\t\tmParameters[paramID] = ParameterValue{ inValue };\n\t\t\t\tAUSDK_RT_UNSAFE_END\n\t\t\t}\n\t\t} else {\n\t\t\t// paramID already exists in map so simply change its value\n\t\t\ti->second.store(inValue, std::memory_order_release);\n\t\t}\n\t}\n\treturn {};\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUElement::SetScheduledEvent(AudioUnitParameterID paramID,\n\tconst AudioUnitParameterEvent& inEvent, UInt32 /*inSliceOffsetInBuffer*/,\n\tUInt32 /*inSliceDurationFrames*/, bool okWhenInitialized) AUSDK_RTSAFE\n{\n\tif (inEvent.eventType != kParameterEvent_Immediate) {\n\t\tAUSDK_LogError_RT(\"Warning: %s was passed a ramped parameter event but does not implement \"\n\t\t\t\t\t\t  \"them. Ignoring.\",\n\t\t\tmAudioUnit.GetLoggingString());\n\t\treturn -2;\n\t}\n\tconst auto res = SetParameterOrError(\n\t\tparamID, inEvent.eventValues.immediate.value, okWhenInitialized); // NOLINT\n\treturn res ? noErr : res.error();\n}\n\n//_____________________________________________________________________________\n//\nvoid AUElement::GetParameterList(AudioUnitParameterID* outList)\n{\n\tif (mUseIndexedParameters) {\n\t\tconst auto numParams = std::ssize(mIndexedParameters);\n\t\tstd::iota(outList, std::next(outList, numParams), 0);\n\t} else {\n\t\tstd::ranges::transform(\n\t\t\tmParameters, outList, [](const auto& keyValue) { return keyValue.first; });\n\t}\n}\n\n//_____________________________________________________________________________\n//\nstatic void AppendBytes(CFMutableDataRef data, const TriviallyCopySerializable auto& value)\n{\n\tCFDataAppendBytes(data, reinterpret_cast<const UInt8*>(&value), sizeof(value)); // NOLINT\n}\n\n//_____________________________________________________________________________\n//\nvoid AUElement::SaveState(AudioUnitScope scope, CFMutableDataRef data)\n{\n\tAudioUnitParameterInfo paramInfo{};\n\tconst auto countOffset = CFDataGetLength(data);\n\tuint32_t paramsWritten = 0;\n\n\tconst auto appendParameter = [&](AudioUnitParameterID paramID, AudioUnitParameterValue value) {\n\t\tif (mAudioUnit.GetParameterInfo(scope, paramID, paramInfo) == noErr) {\n\t\t\tif ((paramInfo.flags & kAudioUnitParameterFlag_CFNameRelease) != 0u) {\n\t\t\t\tif (paramInfo.cfNameString != nullptr) {\n\t\t\t\t\tCFRelease(paramInfo.cfNameString);\n\t\t\t\t}\n\t\t\t\tif (paramInfo.unit == kAudioUnitParameterUnit_CustomUnit &&\n\t\t\t\t\tparamInfo.unitName != nullptr) {\n\t\t\t\t\tCFRelease(paramInfo.unitName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (((paramInfo.flags & kAudioUnitParameterFlag_OmitFromPresets) != 0u) ||\n\t\t\t\t((paramInfo.flags & kAudioUnitParameterFlag_MeterReadOnly) != 0u)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tAppendBytes(data, CFSwapInt32HostToBig(paramID));\n\t\tAppendBytes(data, CFSwapInt32HostToBig(std::bit_cast<UInt32>(value)));\n\n\t\t++paramsWritten;\n\t};\n\n\tconstexpr UInt32 placeholderCount = 0;\n\tAppendBytes(data, placeholderCount);\n\n\tif (mUseIndexedParameters) {\n\t\tconst auto numParams = static_cast<UInt32>(mIndexedParameters.size());\n\t\tfor (UInt32 i = 0; i < numParams; i++) {\n\t\t\tappendParameter(i, mIndexedParameters[i]);\n\t\t}\n\t} else {\n\t\tfor (const auto& item : mParameters) {\n\t\t\tappendParameter(item.first, item.second);\n\t\t}\n\t}\n\n\tconst auto count_BE = CFSwapInt32HostToBig(paramsWritten);\n\tmemcpy(CFDataGetMutableBytePtr(data) + countOffset, // NOLINT ptr math\n\t\t&count_BE, sizeof(count_BE));\n}\n\n//_____________________________________________________________________________\n//\nconst UInt8* AUElement::RestoreState(const UInt8* state)\n{\n\tconst UInt8* p = state;\n\tconst auto numParams = DeserializeBigUInt32AndAdvance(p);\n\n\tfor (UInt32 i = 0; i < numParams; ++i) {\n\t\tconst auto parameterID = DeserializeBigUInt32AndAdvance(p);\n\t\tconst auto valueBytes = DeserializeBigUInt32AndAdvance(p);\n\t\tconst auto value = std::bit_cast<AudioUnitParameterValue>(valueBytes);\n\n\t\tstd::ignore = SetParameterOrError(parameterID, value);\n\t}\n\treturn p;\n}\n\n//_____________________________________________________________________________\n//\nAUIOElement::AUIOElement(AUBase& audioUnit) : AUElement(audioUnit), mWillAllocate(true)\n{\n\tmStreamFormat = AudioStreamBasicDescription{ .mSampleRate = AUBase::kAUDefaultSampleRate,\n\t\t.mFormatID = kAudioFormatLinearPCM,\n\t\t.mFormatFlags = AudioFormatFlags(kAudioFormatFlagsNativeFloatPacked) |\n\t\t\t\t\t\tAudioFormatFlags(kAudioFormatFlagIsNonInterleaved), // NOLINT\n\t\t.mBytesPerPacket = sizeof(float),\n\t\t.mFramesPerPacket = 1,\n\t\t.mBytesPerFrame = sizeof(float),\n\t\t.mChannelsPerFrame = 2,\n\t\t.mBitsPerChannel = 32, // NOLINT\n\t\t.mReserved = 0 };\n}\n\n//_____________________________________________________________________________\n//\nOSStatus AUIOElement::SetStreamFormat(const AudioStreamBasicDescription& format)\n{\n\tmStreamFormat = format;\n\n\t// Clear the previous channel layout if it is inconsistent with the newly set format;\n\t// preserve it if it is acceptable, in case the new format has no layout.\n\tif (ChannelLayout().IsValid() && NumberChannels() != ChannelLayout().NumberChannels()) {\n\t\tRemoveAudioChannelLayout();\n\t}\n\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n// inFramesToAllocate == 0 implies the AudioUnit's max-frames-per-slice will be used\nvoid AUIOElement::AllocateBuffer(UInt32 inFramesToAllocate)\n{\n\tif (GetAudioUnit().HasBegunInitializing()) {\n\t\tUInt32 framesToAllocate =\n\t\t\tinFramesToAllocate > 0 ? inFramesToAllocate : GetAudioUnit().GetMaxFramesPerSlice();\n\n\t\tmIOBuffer.Allocate(\n\t\t\tmStreamFormat, (mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0);\n\t}\n}\n\n//_____________________________________________________________________________\n//\nvoid AUIOElement::DeallocateBuffer() { mIOBuffer.Deallocate(); }\n\n//_____________________________________________________________________________\n//\n//\t\tAudioChannelLayout support\n\n// return an empty vector (ie. NO channel layouts) if the AU doesn't require channel layout\n// knowledge\nstd::vector<AudioChannelLayoutTag> AUIOElement::GetChannelLayoutTags() { return {}; }\n\n// outLayoutPtr WILL be NULL if called to determine layout size\nUInt32 AUIOElement::GetAudioChannelLayout(AudioChannelLayout* outLayoutPtr, bool& outWritable)\n{\n\toutWritable = true;\n\n\tUInt32 size = mChannelLayout.IsValid() ? mChannelLayout.Size() : 0;\n\tif (size > 0 && outLayoutPtr != nullptr) {\n\t\tmemcpy(outLayoutPtr, &mChannelLayout.Layout(), size);\n\t}\n\n\treturn size;\n}\n\n// the incoming channel map will be at least as big as a basic AudioChannelLayout\n// but its contents will determine its actual size\n// Subclass should overide if channel map is writable\nOSStatus AUIOElement::SetAudioChannelLayout(const AudioChannelLayout& inLayout)\n{\n\tAUSDK_Require(NumberChannels() == AUChannelLayout::NumberChannels(inLayout),\n\t\tkAudioUnitErr_InvalidPropertyValue);\n\tmChannelLayout = inLayout;\n\treturn noErr;\n}\n\n// Some units support optional usage of channel maps - typically converter units\n// that can do channel remapping between different maps. In that optional case\n// the user should be able to remove a channel map if that is possible.\n// Typically this is NOT the case (e.g., the 3DMixer even in the stereo case\n// needs to know if it is rendering to speakers or headphones)\nOSStatus AUIOElement::RemoveAudioChannelLayout()\n{\n\tmChannelLayout = {};\n\treturn noErr;\n}\n\n//_____________________________________________________________________________\n//\nvoid AUScope::SetNumberOfElements(UInt32 numElements)\n{\n\tif (mDelegate != nullptr) {\n\t\treturn mDelegate->SetNumberOfElements(numElements);\n\t}\n\n\tif (numElements > mElements.size()) {\n\t\tmElements.reserve(numElements);\n\t\twhile (numElements > mElements.size()) {\n\t\t\tauto elem = mCreator->CreateElement(GetScope(), static_cast<UInt32>(mElements.size()));\n\t\t\tmElements.push_back(std::move(elem));\n\t\t}\n\t} else {\n\t\twhile (numElements < mElements.size()) {\n\t\t\tmElements.pop_back();\n\t\t}\n\t}\n}\n\n//_____________________________________________________________________________\n//\nbool AUScope::HasElementWithName() const\n{\n\tfor (UInt32 i = 0; i < GetNumberOfElements(); ++i) {\n\t\tconst ExpectedPtr<AUElement> el = GetElementOrError(i);\n\t\tif (el && el->HasName()) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n//_____________________________________________________________________________\n//\n\nvoid AUScope::AddElementNamesToDict(CFMutableDictionaryRef inNameDict) const\n{\n\tif (HasElementWithName()) {\n\t\tconst auto elementDict =\n\t\t\tOwned<CFMutableDictionaryRef>::from_create(CFDictionaryCreateMutable(\n\t\t\t\tnullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));\n\t\tfor (UInt32 i = 0; i < GetNumberOfElements(); ++i) {\n\t\t\tconst ExpectedPtr<AUElement> el = GetElementOrError(i);\n\t\t\tif (el && el->HasName()) {\n\t\t\t\tconst auto key = Owned<CFStringRef>::from_create(CFStringCreateWithFormat(\n\t\t\t\t\tnullptr, nullptr, CFSTR(\"%u\"), static_cast<unsigned>(i)));\n\t\t\t\tCFDictionarySetValue(*elementDict, *key, *el->GetName());\n\t\t\t}\n\t\t}\n\n\t\tconst auto key = Owned<CFStringRef>::from_create(\n\t\t\tCFStringCreateWithFormat(nullptr, nullptr, CFSTR(\"%u\"), static_cast<unsigned>(mScope)));\n\t\tCFDictionarySetValue(inNameDict, *key, *elementDict);\n\t}\n}\n\n//_____________________________________________________________________________\n//\nstd::vector<AudioUnitElement> AUScope::RestoreElementNames(CFDictionaryRef inNameDict) const\n{\n\t// first we have to see if we have enough elements\n\tstd::vector<AudioUnitElement> restoredElements;\n\tconst auto maxElNum = GetNumberOfElements();\n\n\tconst auto dictSize =\n\t\tstatic_cast<size_t>(std::max(CFDictionaryGetCount(inNameDict), CFIndex(0)));\n\tstd::vector<CFStringRef> keys(dictSize);\n\tCFDictionaryGetKeysAndValues(\n\t\tinNameDict, reinterpret_cast<const void**>(keys.data()), nullptr); // NOLINT\n\tfor (size_t i = 0; i < dictSize; i++) {\n\t\tunsigned int intKey = 0;\n\t\tstd::array<char, 32> string{};\n\t\tCFStringGetCString(keys[i], string.data(), string.size(), kCFStringEncodingASCII);\n\t\tconst int result = sscanf(string.data(), \"%u\", &intKey); // NOLINT\n\t\t// check if sscanf succeeded and element index is less than max elements.\n\t\tif ((result != 0) && (static_cast<UInt32>(intKey) < maxElNum)) {\n\t\t\tauto* const elName =\n\t\t\t\tstatic_cast<CFStringRef>(CFDictionaryGetValue(inNameDict, keys[i]));\n\t\t\tif ((elName != nullptr) && (CFGetTypeID(elName) == CFStringGetTypeID())) {\n\t\t\t\tconst ExpectedPtr<AUElement> element = GetElementOrError(intKey);\n\t\t\t\tif (element) {\n\t\t\t\t\telement->SetName(elName);\n\t\t\t\t\trestoredElements.push_back(intKey);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn restoredElements;\n}\n\nvoid AUScope::SaveState(CFMutableDataRef data) const\n{\n\tconst AudioUnitElement elementCount = GetNumberOfElements();\n\tfor (AudioUnitElement elementIndex = 0; elementIndex < elementCount; ++elementIndex) {\n\t\tconst ExpectedPtr<AUElement> element = GetElementOrError(elementIndex);\n\t\tconst UInt32 parameterCount = element ? element->GetNumberOfParameters() : 0u;\n\t\tif (parameterCount > 0) {\n\t\t\tAppendBytes(data, CFSwapInt32HostToBig(GetScope()));\n\t\t\tAppendBytes(data, CFSwapInt32HostToBig(elementIndex));\n\t\t\telement->SaveState(mScope, data);\n\t\t}\n\t}\n}\n\nconst UInt8* AUScope::RestoreState(const UInt8* state) const\n{\n\tconst UInt8* p = state;\n\tconst auto elementIdx = DeserializeBigUInt32AndAdvance(p);\n\tconst ExpectedPtr<AUElement> element = GetElementOrError(elementIdx);\n\tif (!element) {\n\t\tconst auto numParams = DeserializeBigUInt32AndAdvance(p);\n\t\tconstexpr auto entrySize = sizeof(AudioUnitParameterID) + sizeof(AudioUnitParameterValue);\n\t\tp += numParams * entrySize; // NOLINT\n\t} else {\n\t\tp = element->RestoreState(p);\n\t}\n\n\treturn p;\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/ComponentBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/ComponentBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n// self\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/ComponentBase.h>\n\n// std\n#include <mutex>\n\nnamespace ausdk {\n\nstatic OSStatus CB_GetComponentDescription(\n\tAudioComponentInstance inInstance, AudioComponentDescription* outDesc);\n\nstd::recursive_mutex& ComponentBase::InitializationMutex()\n{\n\t__attribute__((no_destroy)) static std::recursive_mutex global;\n\treturn global;\n}\n\nComponentBase::ComponentBase(AudioComponentInstance inInstance) : mComponentInstance(inInstance)\n{\n\t(void)GetComponentDescription();\n}\n\nvoid ComponentBase::DoPostConstructor()\n{\n\tPostConstructorInternal();\n\tPostConstructor();\n}\n\nvoid ComponentBase::DoPreDestructor()\n{\n\tPreDestructor();\n\tPreDestructorInternal();\n}\n\nOSStatus ComponentBase::AP_Open(void* self, AudioComponentInstance compInstance)\n{\n\tOSStatus result = noErr;\n\tconst auto acpi = static_cast<AudioComponentPlugInInstance*>(self);\n\ttry {\n\t\tconst std::lock_guard guard{ InitializationMutex() };\n\n\t\tauto* const cb =\n\t\t\tstatic_cast<ComponentBase*>((*acpi->mConstruct)(&acpi->mInstanceStorage, compInstance));\n\t\tcb->DoPostConstructor(); // allows base class to do additional initialization\n\t\t// once the derived class is fully constructed\n\t\tresult = noErr;\n\t}\n\tAUSDK_Catch(result)\n\tif (result != noErr) {\n\t\tdelete acpi; // NOLINT\n\t}\n\treturn result;\n}\n\nOSStatus ComponentBase::AP_Close(void* self)\n{\n\tOSStatus result = noErr;\n\ttry {\n\t\tconst auto acpi = static_cast<AudioComponentPlugInInstance*>(self);\n\t\tif (const auto acImp =\n\t\t\t\treinterpret_cast<ComponentBase*>(&acpi->mInstanceStorage)) { // NOLINT\n\t\t\tacImp->DoPreDestructor();\n\t\t\t(*acpi->mDestruct)(&acpi->mInstanceStorage);\n\t\t\tfree(self); // NOLINT manual memory management\n\t\t}\n\t}\n\tAUSDK_Catch(result)\n\treturn result;\n}\n\nAudioComponentDescription ComponentBase::GetComponentDescription() const\n{\n\tAudioComponentDescription desc{};\n\n\tif (CB_GetComponentDescription(mComponentInstance, &desc) == noErr) {\n\t\treturn desc;\n\t}\n\n\treturn {};\n}\n\nstatic OSStatus CB_GetComponentDescription(\n\tAudioComponentInstance inInstance, AudioComponentDescription* outDesc)\n{\n\tconst AudioComponent comp = AudioComponentInstanceGetComponent(inInstance);\n\tif (comp != nullptr) {\n\t\treturn AudioComponentGetDescription(comp, outDesc);\n\t}\n\n\treturn kAudio_ParamError;\n}\n\n} // namespace ausdk\n"
  },
  {
    "path": "src/AudioUnitSDK/MusicDeviceBase.cpp",
    "content": "/*!\n\t@file\t\tAudioUnitSDK/MusicDeviceBase.cpp\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#include <AudioUnitSDK/AUConfig.h>\n\n#if AUSDK_HAVE_MUSIC_DEVICE\n\n#include <AudioUnitSDK/AUUtility.h>\n#include <AudioUnitSDK/MusicDeviceBase.h>\n\n#include <AudioToolbox/MusicDevice.h>\n\nnamespace ausdk {\n\nAUSDK_BEGIN_NO_RT_WARNINGS\n\nMusicDeviceBase::MusicDeviceBase(\n\tAudioComponentInstance inInstance, UInt32 numInputs, UInt32 numOutputs, UInt32 numGroups)\n\t: AUBase(inInstance, numInputs, numOutputs, numGroups), AUMIDIBase(*static_cast<AUBase*>(this))\n{\n}\n\nOSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, UInt32& outDataSize, bool& outWritable)\n{\n\tswitch (inID) { // NOLINT if/else\n\tcase kMusicDeviceProperty_InstrumentCount:\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\toutDataSize = sizeof(UInt32);\n\t\toutWritable = false;\n\t\treturn noErr;\n\tdefault: {\n\t\tauto result = AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);\n\n\t\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\t\tresult = AUMIDIBase::DelegateGetPropertyInfo(\n\t\t\t\tinID, inScope, inElement, outDataSize, outWritable);\n\t\t}\n\t\treturn result;\n\t}\n\t}\n}\n\nOSStatus MusicDeviceBase::GetProperty(\n\tAudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)\n{\n\tswitch (inID) { // NOLINT if/else\n\tcase kMusicDeviceProperty_InstrumentCount: {\n\t\tAUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);\n\t\tUInt32 instrumentCount{};\n\t\tconst auto result = GetInstrumentCount(instrumentCount);\n\t\tSerialize(instrumentCount, outData);\n\t\treturn result;\n\t}\n\tdefault: {\n\t\tauto result = AUBase::GetProperty(inID, inScope, inElement, outData);\n\n\t\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\t\tresult = AUMIDIBase::DelegateGetProperty(inID, inScope, inElement, outData);\n\t\t}\n\t\treturn result;\n\t}\n\t}\n}\n\n\nOSStatus MusicDeviceBase::SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,\n\tAudioUnitElement inElement, const void* inData, UInt32 inDataSize)\n\n{\n\n\tOSStatus result = AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize);\n\n\tif (result == kAudioUnitErr_InvalidProperty) {\n\t\tresult = AUMIDIBase::DelegateSetProperty(inID, inScope, inElement, inData, inDataSize);\n\t}\n\n\treturn result;\n}\n\n// For a MusicDevice that doesn't support separate instruments (ie. is mono-timbral)\n// then this call should return an instrument count of zero and noErr\nOSStatus MusicDeviceBase::GetInstrumentCount(UInt32& outInstCount) const\n{\n\toutInstCount = 0;\n\treturn noErr;\n}\n\nOSStatus MusicDeviceBase::HandleNoteOn(\n\tUInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) AUSDK_RTSAFE\n{\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"\n#pragma clang diagnostic ignored \"-Wmissing-designated-field-initializers\"\n\tconst MusicDeviceNoteParams params{ .argCount = 2,\n\t\t.mPitch = static_cast<Float32>(inNoteNumber),\n\t\t.mVelocity = static_cast<Float32>(inVelocity) };\n#pragma clang diagnostic pop\n\treturn StartNote(kMusicNoteEvent_UseGroupInstrument, inChannel, nullptr, inStartFrame, params);\n}\n\nOSStatus MusicDeviceBase::HandleNoteOff(\n\tUInt8 inChannel, UInt8 inNoteNumber, UInt8 /*inVelocity*/, UInt32 inStartFrame) AUSDK_RTSAFE\n{\n\treturn StopNote(inChannel, inNoteNumber, inStartFrame);\n}\n\nAUSDK_END_NO_RT_WARNINGS\n\n} // namespace ausdk\n\n#endif // AUSDK_HAVE_MUSIC_DEVICE\n"
  },
  {
    "path": "tests/AUThreadSafeListTests.mm",
    "content": "/*!\n\t@file\t\tAUThreadSafeListTests.mm\n\t@copyright\t© 2000-2025 Apple Inc. All rights reserved.\n*/\n#import <XCTest/XCTest.h>\n\n#include <AudioUnitSDK/AUThreadSafeList.h>\n#include <AudioUnitSDK/AudioUnitSDK.h>\n#include <algorithm>\n#include <chrono>\n#include <memory>\n#include <thread>\n#include <vector>\n\nclass FauxRenderCallback {\npublic:\n\tFauxRenderCallback() noexcept = default;\n\tbool operator==(const FauxRenderCallback& other) const noexcept = default;\n\n\tuint32_t mValue{ 0 };\n};\n\n@interface AUThreadSafeListTests : XCTestCase\n\n@end\n\n@implementation AUThreadSafeListTests\n\n- (BOOL)continueAfterFailure\n{\n\treturn NO;\n}\n\n- (void)testAdd\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Add(cb);\n\tXCTAssertEqual(list.begin(), list.end());\n\n\tlist.Update();\n\n\tXCTAssertEqual(*list.begin(), cb);\n}\n\n- (void)testAddNoUpdate\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Add(cb);\n\n\t// We should call list.Update() here\n\n\tXCTAssertEqual(list.begin(), list.end());\n}\n\n- (void)testRemove\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Add(cb);\n\tXCTAssertEqual(list.begin(), list.end());\n\n\tlist.Update();\n\tXCTAssertEqual(*list.begin(), cb);\n\n\tlist.Remove(cb);\n\tXCTAssertEqual(*list.begin(), cb);\n\n\tlist.Update();\n\tXCTAssertEqual(list.begin(), list.end());\n}\n\n- (void)testRemoveNoUpdate\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Add(cb);\n\n\tlist.Update();\n\n\tlist.Remove(cb);\n\n\t// We should call list.Update() here\n\n\tXCTAssertEqual(*list.begin(), cb);\n}\n\n- (void)testRemoveOnEmptyList\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Remove(cb);\n\n\tlist.Update();\n\tXCTAssertEqual(list.begin(), list.end());\n}\n\n- (void)testSingleClear\n{\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\t// Add\n\tFauxRenderCallback cb;\n\tcb.mValue = 56;\n\tlist.Add(cb);\n\n\tlist.Update();\n\n\tlist.Clear();\n\n\tlist.Update();\n\n\tXCTAssertEqual(list.begin(), list.end());\n}\n\n- (void)testBasicConsistency\n{\n\tstatic int objCounter = 0;\n\n\tconstexpr auto kTestElements = 10000;\n\tclass CountedObject {\n\tpublic:\n\t\tCountedObject() noexcept { objCounter++; }\n\t\tCountedObject(const CountedObject&) = delete;\n\t\tCountedObject(CountedObject&&) = delete;\n\t\tCountedObject& operator=(const CountedObject&) = default;\n\t\tCountedObject& operator=(CountedObject&&) = default;\n\t\t~CountedObject() noexcept { objCounter--; }\n\n\t\tbool operator==(const CountedObject& other) const noexcept = default;\n\n\t\tuint32_t mValue{ 0 };\n\t};\n\n\tauto getListCount = [](const ausdk::AUThreadSafeList<CountedObject>& list) {\n\t\treturn std::ranges::distance(list);\n\t};\n\n\tauto list = std::make_unique<ausdk::AUThreadSafeList<CountedObject>>();\n\n\tstd::vector<uint32_t> mirrorState;\n\t// Add\n\tfor (uint32_t i = 0; i < kTestElements; ++i) {\n\t\tCountedObject cb;\n\t\tcb.mValue = i;\n\t\tlist->Add(cb);\n\t\tmirrorState.push_back(i);\n\t}\n\n\tlist->Update();\n\tXCTAssertEqual(getListCount(*list), kTestElements);\n\tuint32_t counter = 0;\n\tfor (auto& callback : *list) {\n\t\tXCTAssertEqual(counter, callback.mValue);\n\t\tcounter++;\n\t}\n\n\t// Remove\n\tfor (uint32_t i = 0; i < kTestElements; i += 1000) {\n\t\tCountedObject cb;\n\t\tcb.mValue = i;\n\t\tlist->Remove(cb);\n\t\tstd::erase(mirrorState, i);\n\t}\n\n\tlist->Update();\n\tXCTAssertEqual(getListCount(*list), 9990);\n\n\tstd::vector<uint32_t> removedState;\n\tfor (auto& node : *list) {\n\t\tremovedState.push_back(node.mValue);\n\t}\n\n\tXCTAssertTrue(std::ranges::equal(removedState, mirrorState));\n\n\t// Clear\n\tlist->Clear();\n\tlist->Update();\n\n\tXCTAssertEqual(getListCount(*list), 0);\n\n\t// Re-Add\n\tfor (uint32_t i = 0; i < kTestElements; ++i) {\n\t\tCountedObject cb;\n\t\tcb.mValue = i;\n\t\tlist->Add(cb);\n\t}\n\n\tlist->Update();\n\tXCTAssertEqual(getListCount(*list), kTestElements);\n\n\tlist.reset();\n\tXCTAssertEqual(objCounter, 0);\n}\n\n- (void)testAsyncConsistency\n{\n\tusing sys_clock = std::chrono::system_clock;\n\n\tstatic constexpr auto kTimeout = 5;\n\tconstexpr auto kTestElements = 1000;\n\n\tausdk::AUThreadSafeList<FauxRenderCallback> list;\n\n\tstd::thread t([&list]() {\n\t\tfor (uint32_t i = 0; i < kTestElements; i++) {\n\t\t\tFauxRenderCallback cb;\n\t\t\tcb.mValue = i;\n\t\t\tlist.Add(cb);\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(2));\n\t\t}\n\t});\n\tt.detach();\n\n\tstd::thread t2([&list]() {\n\t\tauto start = sys_clock::now();\n\t\twhile (std::ranges::distance(list) < kTestElements) {\n\t\t\tlist.Update();\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\tif (sys_clock::now() - start > std::chrono::seconds(kTimeout)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\tt2.join();\n\n\tXCTAssertEqual(std::ranges::distance(list), kTestElements);\n\n\tstd::thread t3([&list]() {\n\t\tfor (uint32_t i = 0; i < kTestElements; i++) {\n\t\t\tFauxRenderCallback cb;\n\t\t\tcb.mValue = i;\n\t\t\tlist.Remove(cb);\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(2));\n\t\t}\n\t});\n\tt3.detach();\n\n\tstd::thread t4([&list]() {\n\t\tauto start = std::chrono::system_clock::now();\n\t\twhile (std::ranges::distance(list) > 0) {\n\t\t\tlist.Update();\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\tif (sys_clock::now() - start > std::chrono::seconds(kTimeout)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\tt4.join();\n\n\tXCTAssertEqual(std::ranges::distance(list), 0);\n}\n\n@end\n"
  },
  {
    "path": "tests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/Tests.mm",
    "content": "/*!\n\t@file\t\tTests.mm\n\t@copyright\t© 2020-2025 Apple Inc. All rights reserved.\n*/\n\n#import <XCTest/XCTest.h>\n\n#import <AudioUnitSDK/AudioUnitSDK.h>\n#import <algorithm>\n#import <array>\n#import <cstddef>\n#import <cstring>\n#import <memory>\n#import <span>\n#import <vector>\n\n@interface Tests : XCTestCase\n\n@end\n\n@implementation Tests\n\n- (void)testFlatMap\n{\n\tausdk::flat_map<AudioUnitParameterID, float> uut;\n\tXCTAssertTrue(uut.empty());\n\n\tuut[5] = 5.0;\n\tXCTAssertEqual(uut.size(), 1u);\n\tXCTAssertEqual(uut[5], 5.0);\n\n\tuut[5] = 5.5;\n\tXCTAssertEqual(uut.size(), 1u);\n\tXCTAssertEqual(uut[5], 5.5);\n\n\tuut[1] = 1.0;\n\tXCTAssertEqual(uut.size(), 2u);\n\tXCTAssertEqual(uut[1], 1.0);\n\n\tuut[15] = 15.0;\n\tXCTAssertEqual(uut.size(), 3u);\n\tXCTAssertEqual(uut[15], 15.0);\n\n\tXCTAssertEqual(uut.find(0), uut.end());\n\n\tXCTAssertEqual(uut[1], 1.0);\n\tXCTAssertEqual(uut[5], 5.5);\n\tXCTAssertEqual(uut[15], 15.0);\n}\n\n- (void)testAUBufferList\n{\n\t//\tconstexpr unsigned kLargeBufSize = 512;\n\n\tauto checkBuf = [](const AudioBuffer& buf, unsigned nch, unsigned nbytes, bool nullBuf) {\n\t\tXCTAssertEqual(buf.mNumberChannels, nch);\n\t\tXCTAssertEqual(buf.mDataByteSize, nbytes);\n\t\tif (nullBuf) {\n\t\t\tXCTAssertEqual(buf.mData, nullptr);\n\t\t} else {\n\t\t\tXCTAssertNotEqual(buf.mData, nullptr);\n\t\t}\n\t};\n\tauto checkABL = [&](const AudioBufferList& abl, unsigned nbufs, unsigned nch, unsigned nbytes,\n\t\t\t\t\t\tbool nullBuf) {\n\t\tXCTAssertEqual(abl.mNumberBuffers, nbufs);\n\t\tfor (unsigned idx = 0; idx < nbufs; ++idx) {\n\t\t\tcheckBuf(abl.mBuffers[idx], nch, nbytes, nullBuf);\n\t\t}\n\t};\n\tauto test = [&](const unsigned kNumBufs, const unsigned kFrameCount) {\n\t\tconst auto kBufSize = kFrameCount * sizeof(float);\n\t\tausdk::AUBufferList uut;\n\t\tconst auto asbd = ausdk::ASBD::CreateCommonFloat32(44100.0, kNumBufs);\n\n\t\tuut.Allocate(asbd, kFrameCount);\n\n\t\t// Prepare 0 bytes\n\t\tcheckABL(uut.PrepareBuffer(asbd, 0), kNumBufs, 1, 0, kBufSize == 0);\n\n\t\tif (kBufSize == 0) {\n\t\t\t// XCTAssertThrows(uut.PrepareBuffer(asbd, kLargeBufSize));\n\t\t} else {\n\t\t\tcheckABL(uut.PrepareBuffer(asbd, kFrameCount), kNumBufs, 1, kFrameCount * sizeof(float),\n\t\t\t\tfalse);\n\t\t}\n\n\t\tcheckABL(uut.PrepareNullBuffer(asbd, kFrameCount), kNumBufs, 1, kFrameCount * sizeof(float),\n\t\t\ttrue);\n\t};\n\n\tconstexpr unsigned kTypicalFrameCount = 512;\n\n\ttest(0, 0);\n\ttest(1, 0);\n\ttest(1, kTypicalFrameCount);\n\ttest(2, kTypicalFrameCount);\n\ttest(3, kTypicalFrameCount);\n\ttest(4, kTypicalFrameCount);\n}\n\n- (void)testSerialize\n{\n\tconstexpr float value = 123456789.f;\n\tstd::vector<std::byte> data(sizeof(value));\n\tausdk::Serialize(value, data.data());\n\tXCTAssertEqual(std::memcmp(&value, data.data(), data.size()), 0);\n\n\t// unaligned memory\n\tconstexpr size_t offset = 1;\n\tconst auto valueMemory = std::make_unique<std::byte[]>(sizeof(value) + offset);\n\tconst auto valueAddress = valueMemory.get() + offset;\n\tausdk::Serialize<float>(value, valueAddress);\n\tXCTAssertEqual(std::memcmp(&value, valueAddress, sizeof(value)), 0);\n\n\tconst std::vector<int> values({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });\n\tdata.clear();\n\tdata.resize(std::span(values).size_bytes());\n\tausdk::Serialize(std::span(values), data.data());\n\tXCTAssertEqual(std::memcmp(values.data(), data.data(), data.size()), 0);\n}\n\n- (void)testDeserialize\n{\n\tconstexpr float value = 987654321.f;\n\tXCTAssertEqual(ausdk::Deserialize<float>(&value), value);\n\n\t// unaligned memory\n\tconstexpr size_t offset = 1;\n\tconst auto valueMemory = std::make_unique<std::byte[]>(sizeof(value) + offset);\n\tconst auto valueAddress = valueMemory.get() + offset;\n\tstd::memcpy(valueAddress, &value, sizeof(value));\n\tXCTAssertEqual(ausdk::Deserialize<float>(valueAddress), value);\n\n\tconst std::vector<int> values({ 9, 8, 7, 6, 5, 4, 3, 2, 1 });\n\tXCTAssertTrue(std::ranges::equal(\n\t\tausdk::DeserializeArray<int>(values.data(), std::span(values).size_bytes()), values));\n}\n\n- (void)testDeserializeBigUInt32AndAdvance\n{\n\tconst auto data = std::to_array({ CFSwapInt32HostToBig(1), CFSwapInt32HostToBig(11),\n\t\tCFSwapInt32HostToBig(1'000'000'000), CFSwapInt32HostToBig(0), CFSwapInt32HostToBig(99) });\n\tauto pointer = reinterpret_cast<const UInt8*>(data.data());\n\tXCTAssertEqual(ausdk::DeserializeBigUInt32AndAdvance(pointer), 1u);\n\tXCTAssertEqual(ausdk::DeserializeBigUInt32AndAdvance(pointer), 11u);\n\tXCTAssertEqual(ausdk::DeserializeBigUInt32AndAdvance(pointer), 1'000'000'000u);\n\tXCTAssertEqual(ausdk::DeserializeBigUInt32AndAdvance(pointer), 0u);\n\tXCTAssertEqual(ausdk::DeserializeBigUInt32AndAdvance(pointer), 99u);\n\tXCTAssertEqual(pointer, static_cast<const void*>(data.cend()));\n}\n\n- (void)testMakeStringFrom4CC\n{\n\tXCTAssertEqual(ausdk::MakeStringFrom4CC('abcd'), \"abcd\");\n\tXCTAssertEqual(ausdk::MakeStringFrom4CC('1234' + 0x7F), \"123.\");\n}\n\n#if AUSDK_LOOSE_RT_SAFETY\n\nnamespace {\n\nclass ThrowsDuringRender : public ausdk::AUBase {\npublic:\n\tThrowsDuringRender() : ausdk::AUBase(nullptr, 1, 1) {}\n\n\tbool CanScheduleParameters() const noexcept AUSDK_RTSAFE override { return false; }\n\tbool StreamFormatWritable(AudioUnitScope, AudioUnitElement) override { return true; }\n\n    AUSDK_BEGIN_NO_RT_NOEXCEPT_WARNINGS\n\tvirtual OSStatus Render(AudioUnitRenderActionFlags& /*ioActionFlags*/,\n\t\tconst AudioTimeStamp& /*inTimeStamp*/, UInt32 /*inNumberFrames*/) AUSDK_RTSAFE override\n\t{\n\t\tthrow OSStatus(42);\n\t}\n\n\tvirtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags&, const AudioBufferList&,\n\t\tAudioBufferList&, UInt32) AUSDK_RTSAFE override\n\t{\n\t\tthrow OSStatus(43);\n\t}\n    AUSDK_END_NO_RT_NOEXCEPT_WARNINGS\n};\n\nclass ThrowsDuringRenderFixture {\npublic:\n\tconstexpr static UInt32 kRenderFrameCount = 512;\n\n\tThrowsDuringRender uut;\n\tausdk::AUBufferList buf;\n\n\tThrowsDuringRenderFixture()\n\t{\n\t\tuut.DoPostConstructor();\n\n\t\tauto inputProc = +[](void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32,\n\t\t\t\t\t\t\t  UInt32, AudioBufferList*) -> OSStatus { return noErr; };\n\n\t\tuut.Input(0).SetInputCallback(inputProc, nullptr);\n\n\t\tOSStatus err = uut.DoInitialize();\n\t\tXCTAssertEqual(err, noErr);\n\n\t\tAudioStreamBasicDescription format = uut.GetStreamFormat(kAudioUnitScope_Output, 0);\n\t\tbuf.Allocate(format, kRenderFrameCount);\n\t\tbuf.PrepareNullBuffer(format, kRenderFrameCount);\n\t}\n\n\tvoid Render()\n\t{\n\t\tAudioUnitRenderActionFlags flags = 0;\n\t\tAudioTimeStamp ts{};\n\n\t\tOSStatus err = uut.DoRender(flags, ts, 0, kRenderFrameCount, buf.GetBufferList());\n\t\tXCTAssertEqual(err, 42);\n\t}\n\n\tvoid Process()\n\t{\n\t\tAudioUnitRenderActionFlags flags = 0;\n\t\tAudioTimeStamp ts{};\n\n\t\tOSStatus err = uut.DoProcess(flags, ts, kRenderFrameCount, buf.GetBufferList());\n\t\tXCTAssertEqual(err, 43);\n\t}\n};\n\n} // anonymous namespace\n\n- (void)testThrowsDuringRender\n{\n\tThrowsDuringRenderFixture f;\n\tf.Render();\n}\n\n- (void)testThrowsDuringProcess\n{\n\tThrowsDuringRenderFixture f;\n\tf.Process();\n}\n\n#endif // AUSDK_LOOSE_RT_SAFETY\n\n@end\n"
  },
  {
    "path": "tools/FindUB.sh",
    "content": "#! /bin/sh\n\n# Certain types can only safely be accessed through pointers, not C++ references.\n# This is due to their being variably-sized. <rdar://91434355>\n# Find code that uses references to the problem types.\n\nSearchDir=\"$1\"\n\nif [ -z \"$SearchDir\" ] ; then\n\tSearchDir=.\nfi\n\negrep -r \"(AURenderEvent|MIDI(Packet|Event)List)\\s*(const\\s*)?&\" \"$SearchDir\"\nif [ $? -eq 0 ]; then\n  echo \"error: forming reference to a type which causes UB <rdar://91434355>\"\n  exit 1 \nfi\n"
  },
  {
    "path": "tools/build.sh",
    "content": "#! /bin/sh\n\n# Assumes the root of the project is the current directory\n\nSDK=$1\nDEST=\"$2\"\n\nif [ -z \"$DEST\" ] ; then\n\techo \"usage: build.sh SDK DEST\"\n\texit 1\nfi\n\nxcodebuild install -configuration Release -sdk $SDK DSTROOT=\"$DEST\" || exit 1\n"
  }
]