PXR_Audio_Spatializer_Context.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. // Copyright © 2015-2022 Pico Technology Co., Ltd. All Rights Reserved.
  2. using System;
  3. using System.Collections;
  4. using PXR_Audio.Spatializer;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. #if UNITY_EDITOR
  8. using UnityEditor;
  9. #endif
  10. public partial class PXR_Audio_Spatializer_Context : MonoBehaviour
  11. {
  12. [SerializeField] public SpatializerApiImpl spatializerApiImpl = SpatializerApiImpl.unity;
  13. private static PXR_Audio.Spatializer.Api _api = null;
  14. #if UNITY_EDITOR
  15. private static SpatializerApiImpl _lastSpatializerApiImpl;
  16. #endif
  17. public PXR_Audio.Spatializer.Api PXR_Audio_Spatializer_Api
  18. {
  19. get
  20. {
  21. #if UNITY_EDITOR
  22. if (_api == null ||
  23. (_lastSpatializerApiImpl != spatializerApiImpl && !EditorApplication.isPlaying))
  24. #else
  25. if (_api == null)
  26. #endif
  27. {
  28. if (spatializerApiImpl == SpatializerApiImpl.unity)
  29. _api = new ApiUnityImpl();
  30. else if (spatializerApiImpl == SpatializerApiImpl.wwise)
  31. _api = new ApiWwiseImpl();
  32. #if UNITY_EDITOR
  33. _lastSpatializerApiImpl = spatializerApiImpl;
  34. #endif
  35. }
  36. return _api;
  37. }
  38. }
  39. private static PXR_Audio_Spatializer_Context _instance;
  40. public static PXR_Audio_Spatializer_Context Instance => _instance;
  41. private IntPtr context = IntPtr.Zero;
  42. private bool initialized = false;
  43. private bool isSceneDirty = false;
  44. public bool Initialized
  45. {
  46. get => initialized;
  47. }
  48. [SerializeField]
  49. private PXR_Audio.Spatializer.RenderingMode renderingQuality = PXR_Audio.Spatializer.RenderingMode.MediumQuality;
  50. #region EDITOR-ONLY SerializedFields
  51. #if UNITY_EDITOR
  52. [SerializeField, HideInInspector] private LayerMask meshBakingLayerMask = ~0;
  53. #endif
  54. #endregion
  55. public PXR_Audio.Spatializer.RenderingMode RenderingQuality => renderingQuality;
  56. [SerializeField] private UnityEvent preInitEvent;
  57. [SerializeField] private UnityEvent lateInitEvent;
  58. private AudioConfiguration audioConfig;
  59. public AudioConfiguration AudioConfig => audioConfig;
  60. private bool bypass = true;
  61. private bool Bypass => bypass;
  62. static int uuidCounter = 0;
  63. private static int GetUuid()
  64. {
  65. var temp = uuidCounter;
  66. uuidCounter = (uuidCounter == Int32.MaxValue) ? 0 : (uuidCounter + 1);
  67. return temp;
  68. }
  69. private int uuid = -1;
  70. public int UUID => uuid;
  71. public PXR_Audio.Spatializer.Result SubmitMesh(
  72. float[] vertices,
  73. int verticesCount,
  74. int[] indices,
  75. int indicesCount,
  76. PXR_Audio.Spatializer.AcousticsMaterial material,
  77. ref int geometryId)
  78. {
  79. isSceneDirty = true;
  80. return PXR_Audio_Spatializer_Api.SubmitMesh(
  81. context,
  82. vertices,
  83. verticesCount,
  84. indices,
  85. indicesCount,
  86. material,
  87. ref geometryId);
  88. }
  89. public PXR_Audio.Spatializer.Result SubmitMeshAndMaterialFactor(
  90. float[] vertices,
  91. int verticesCount,
  92. int[] indices,
  93. int indicesCount,
  94. float[] absorptionFactor,
  95. float scatteringFactor,
  96. float transmissionFactor,
  97. ref int geometryId)
  98. {
  99. isSceneDirty = true;
  100. return PXR_Audio_Spatializer_Api.SubmitMeshAndMaterialFactor(
  101. context,
  102. vertices,
  103. verticesCount,
  104. indices,
  105. indicesCount,
  106. absorptionFactor,
  107. scatteringFactor,
  108. transmissionFactor,
  109. ref geometryId);
  110. }
  111. public Result SubmitMeshWithConfig(float[] vertices, int verticesCount, int[] indices, int indicesCount,
  112. ref MeshConfig config, ref int geometryId)
  113. {
  114. isSceneDirty = true;
  115. return PXR_Audio_Spatializer_Api.SubmitMeshWithConfig(context, vertices, verticesCount, indices, indicesCount,
  116. ref config, ref geometryId);
  117. }
  118. public Result RemoveMesh(int geometryId)
  119. {
  120. isSceneDirty = true;
  121. return PXR_Audio_Spatializer_Api.RemoveMesh(context, geometryId);
  122. }
  123. public Result SetMeshConfig(int geometryId, ref MeshConfig config, uint propertyMask)
  124. {
  125. isSceneDirty = true;
  126. return PXR_Audio_Spatializer_Api.SetMeshConfig(context, geometryId, ref config, propertyMask);
  127. }
  128. public PXR_Audio.Spatializer.Result AddSource(
  129. PXR_Audio.Spatializer.SourceMode sourceMode,
  130. float[] position,
  131. ref int sourceId,
  132. bool isAsync = false)
  133. {
  134. return PXR_Audio_Spatializer_Api.AddSource(
  135. context,
  136. sourceMode,
  137. position,
  138. ref sourceId,
  139. isAsync);
  140. }
  141. public PXR_Audio.Spatializer.Result AddSourceWithOrientation(
  142. PXR_Audio.Spatializer.SourceMode mode,
  143. float[] position,
  144. float[] front,
  145. float[] up,
  146. float radius,
  147. ref int sourceId,
  148. bool isAsync)
  149. {
  150. return PXR_Audio_Spatializer_Api.AddSourceWithOrientation(
  151. context,
  152. mode,
  153. position,
  154. front,
  155. up,
  156. radius,
  157. ref sourceId,
  158. isAsync);
  159. }
  160. public PXR_Audio.Spatializer.Result AddSourceWithConfig(
  161. ref PXR_Audio.Spatializer.SourceConfig sourceConfig,
  162. ref int sourceId,
  163. bool isAsync)
  164. {
  165. return PXR_Audio_Spatializer_Api.AddSourceWithConfig(context, ref sourceConfig, ref sourceId, isAsync);
  166. }
  167. public Result SetSourceConfig(int sourceId, ref SourceConfig sourceConfig, uint propertyMask)
  168. {
  169. return PXR_Audio_Spatializer_Api.SetSourceConfig(context, sourceId, ref sourceConfig, propertyMask);
  170. }
  171. public PXR_Audio.Spatializer.Result SetSourceAttenuationMode(int sourceId,
  172. PXR_Audio.Spatializer.SourceAttenuationMode mode,
  173. PXR_Audio.Spatializer.DistanceAttenuationCallback directDistanceAttenuationCallback = null,
  174. PXR_Audio.Spatializer.DistanceAttenuationCallback indirectDistanceAttenuationCallback = null)
  175. {
  176. return PXR_Audio_Spatializer_Api.SetSourceAttenuationMode(context, sourceId, mode,
  177. directDistanceAttenuationCallback, indirectDistanceAttenuationCallback);
  178. }
  179. public PXR_Audio.Spatializer.Result SetSourceRange(int sourceId, float rangeMin, float rangeMax)
  180. {
  181. return PXR_Audio_Spatializer_Api.SetSourceRange(context, sourceId, rangeMin, rangeMax);
  182. }
  183. public PXR_Audio.Spatializer.Result RemoveSource(int sourceId)
  184. {
  185. return PXR_Audio_Spatializer_Api.RemoveSource(context, sourceId);
  186. }
  187. public PXR_Audio.Spatializer.Result SubmitSourceBuffer(
  188. int sourceId,
  189. float[] inputBufferPtr,
  190. uint numFrames)
  191. {
  192. return PXR_Audio_Spatializer_Api.SubmitSourceBuffer(
  193. context,
  194. sourceId,
  195. inputBufferPtr,
  196. numFrames);
  197. }
  198. public PXR_Audio.Spatializer.Result SubmitAmbisonicChannelBuffer(
  199. float[] ambisonicChannelBuffer,
  200. int order,
  201. int degree,
  202. PXR_Audio.Spatializer.AmbisonicNormalizationType normType,
  203. float gain)
  204. {
  205. return PXR_Audio_Spatializer_Api.SubmitAmbisonicChannelBuffer(
  206. context,
  207. ambisonicChannelBuffer,
  208. order,
  209. degree,
  210. normType,
  211. gain);
  212. }
  213. public PXR_Audio.Spatializer.Result SubmitInterleavedAmbisonicBuffer(
  214. float[] ambisonicBuffer,
  215. int ambisonicOrder,
  216. PXR_Audio.Spatializer.AmbisonicNormalizationType normType,
  217. float gain)
  218. {
  219. return PXR_Audio_Spatializer_Api.SubmitInterleavedAmbisonicBuffer(
  220. context,
  221. ambisonicBuffer,
  222. ambisonicOrder,
  223. normType,
  224. gain);
  225. }
  226. public PXR_Audio.Spatializer.Result SubmitMatrixInputBuffer(
  227. float[] inputBuffer,
  228. int inputChannelIndex)
  229. {
  230. return PXR_Audio_Spatializer_Api.SubmitMatrixInputBuffer(
  231. context,
  232. inputBuffer,
  233. inputChannelIndex);
  234. }
  235. public PXR_Audio.Spatializer.Result GetInterleavedBinauralBuffer(
  236. float[] outputBufferPtr,
  237. uint numFrames,
  238. bool isAccumulative)
  239. {
  240. return PXR_Audio_Spatializer_Api.GetInterleavedBinauralBuffer(
  241. context,
  242. outputBufferPtr,
  243. numFrames,
  244. isAccumulative);
  245. }
  246. public PXR_Audio.Spatializer.Result GetPlanarBinauralBuffer(
  247. float[][] outputBufferPtr,
  248. uint numFrames,
  249. bool isAccumulative)
  250. {
  251. return PXR_Audio_Spatializer_Api.GetPlanarBinauralBuffer(
  252. context,
  253. outputBufferPtr,
  254. numFrames,
  255. isAccumulative);
  256. }
  257. public PXR_Audio.Spatializer.Result GetInterleavedLoudspeakersBuffer(
  258. float[] outputBufferPtr,
  259. uint numFrames)
  260. {
  261. return PXR_Audio_Spatializer_Api.GetInterleavedLoudspeakersBuffer(
  262. context,
  263. outputBufferPtr,
  264. numFrames);
  265. }
  266. public PXR_Audio.Spatializer.Result GetPlanarLoudspeakersBuffer(
  267. float[][] outputBufferPtr,
  268. uint numFrames)
  269. {
  270. return PXR_Audio_Spatializer_Api.GetPlanarLoudspeakersBuffer(
  271. context,
  272. outputBufferPtr,
  273. numFrames);
  274. }
  275. public PXR_Audio.Spatializer.Result SetPlaybackMode(
  276. PXR_Audio.Spatializer.PlaybackMode playbackMode)
  277. {
  278. return PXR_Audio_Spatializer_Api.SetPlaybackMode(
  279. context,
  280. playbackMode);
  281. }
  282. public PXR_Audio.Spatializer.Result SetLoudspeakerArray(
  283. float[] positions,
  284. int numLoudspeakers)
  285. {
  286. return PXR_Audio_Spatializer_Api.SetLoudspeakerArray(
  287. context,
  288. positions,
  289. numLoudspeakers);
  290. }
  291. public PXR_Audio.Spatializer.Result SetMappingMatrix(
  292. float[] matrix,
  293. int numInputChannels,
  294. int numOutputChannels)
  295. {
  296. return PXR_Audio_Spatializer_Api.SetMappingMatrix(
  297. context,
  298. matrix,
  299. numInputChannels,
  300. numOutputChannels);
  301. }
  302. public PXR_Audio.Spatializer.Result SetListenerPosition(
  303. float[] position)
  304. {
  305. return PXR_Audio_Spatializer_Api.SetListenerPosition(
  306. context,
  307. position);
  308. }
  309. public PXR_Audio.Spatializer.Result SetListenerOrientation(
  310. float[] front,
  311. float[] up)
  312. {
  313. return PXR_Audio_Spatializer_Api.SetListenerOrientation(
  314. context,
  315. front,
  316. up);
  317. }
  318. public PXR_Audio.Spatializer.Result SetListenerPose(
  319. float[] position,
  320. float[] front,
  321. float[] up)
  322. {
  323. return PXR_Audio_Spatializer_Api.SetListenerPose(
  324. context,
  325. position,
  326. front,
  327. up);
  328. }
  329. public PXR_Audio.Spatializer.Result SetSourcePosition(
  330. int sourceId,
  331. float[] position)
  332. {
  333. return PXR_Audio_Spatializer_Api.SetSourcePosition(
  334. context,
  335. sourceId,
  336. position);
  337. }
  338. public PXR_Audio.Spatializer.Result SetSourceGain(
  339. int sourceId,
  340. float gain)
  341. {
  342. return PXR_Audio_Spatializer_Api.SetSourceGain(
  343. context,
  344. sourceId,
  345. gain);
  346. }
  347. public PXR_Audio.Spatializer.Result SetSourceSize(
  348. int sourceId,
  349. float volumetricSize)
  350. {
  351. return PXR_Audio_Spatializer_Api.SetSourceSize(
  352. context,
  353. sourceId,
  354. volumetricSize);
  355. }
  356. public PXR_Audio.Spatializer.Result UpdateSourceMode(
  357. int sourceId,
  358. PXR_Audio.Spatializer.SourceMode mode)
  359. {
  360. return PXR_Audio_Spatializer_Api.UpdateSourceMode(
  361. context,
  362. sourceId,
  363. mode);
  364. }
  365. public PXR_Audio.Spatializer.Result SetDopplerEffect(int sourceId, bool on)
  366. {
  367. return PXR_Audio_Spatializer_Api.SetDopplerEffect(context, sourceId, on);
  368. }
  369. void OnAudioConfigurationChangedEventHandler(bool deviceWasChanged)
  370. {
  371. audioConfig = AudioSettings.GetConfiguration();
  372. ResetContext(renderingQuality);
  373. }
  374. /// <summary>
  375. /// Setup Spatializer rendering quality.
  376. /// </summary>
  377. /// <param name="quality">Rendering quality preset.</param>
  378. public void SetRenderingQuality(PXR_Audio.Spatializer.RenderingMode quality)
  379. {
  380. renderingQuality = quality;
  381. AudioSettings.Reset(AudioSettings.GetConfiguration());
  382. Debug.Log("Pico Spatializer has set rendering quality to: " + renderingQuality);
  383. }
  384. private void OnEnable()
  385. {
  386. if (_instance == null)
  387. {
  388. _instance = this;
  389. AudioSettings.OnAudioConfigurationChanged += OnAudioConfigurationChangedEventHandler;
  390. // Create context
  391. StartInternal(renderingQuality);
  392. Debug.Log("Pico Spatializer Initialized.");
  393. DontDestroyOnLoad(this);
  394. }
  395. else if (_instance != this)
  396. {
  397. Destroy(this);
  398. }
  399. }
  400. private void StartInternal(PXR_Audio.Spatializer.RenderingMode quality)
  401. {
  402. preInitEvent.Invoke();
  403. uuid = GetUuid();
  404. PXR_Audio.Spatializer.Result ret = Result.Success;
  405. audioConfig = AudioSettings.GetConfiguration();
  406. ret = PXR_Audio_Spatializer_Api.CreateContext(
  407. ref context,
  408. quality,
  409. (uint)audioConfig.dspBufferSize,
  410. (uint)audioConfig.sampleRate);
  411. if (ret != PXR_Audio.Spatializer.Result.Success)
  412. {
  413. Debug.LogError("Failed to create context, error code: " + ret);
  414. }
  415. ret = PXR_Audio_Spatializer_Api.InitializeContext(context);
  416. if (ret != PXR_Audio.Spatializer.Result.Success)
  417. {
  418. Debug.LogError("Failed to initialize context, error code: " + ret);
  419. }
  420. // Add all the geometries back
  421. PXR_Audio_Spatializer_SceneGeometry[] geometries = FindObjectsOfType<PXR_Audio_Spatializer_SceneGeometry>();
  422. for (int geoId = 0; geoId < geometries.Length; ++geoId)
  423. {
  424. // For all found geometry and material pair, submit them into Pico spatializer
  425. geometries[geoId].SubmitMeshToContext();
  426. geometries[geoId].SubmitStaticMeshToContext();
  427. if (ret != PXR_Audio.Spatializer.Result.Success)
  428. {
  429. Debug.LogError("Failed to submit geometry #" + geoId + ", error code: " + ret);
  430. }
  431. }
  432. ret = PXR_Audio_Spatializer_Api.CommitScene(context);
  433. if (ret != PXR_Audio.Spatializer.Result.Success)
  434. {
  435. Debug.LogError("Failed to commit scene, error code: " + ret);
  436. }
  437. lateInitEvent.Invoke();
  438. initialized = true;
  439. if (spatializerApiImpl != SpatializerApiImpl.wwise)
  440. {
  441. // Add all the sources back
  442. PXR_Audio_Spatializer_AudioSource[] sources = FindObjectsOfType<PXR_Audio_Spatializer_AudioSource>();
  443. for (int i = 0; i < sources.Length; ++i)
  444. {
  445. sources[i].RegisterInternal();
  446. }
  447. }
  448. // Add listener back
  449. PXR_Audio_Spatializer_AudioListener listener = FindObjectOfType<PXR_Audio_Spatializer_AudioListener>();
  450. listener.RegisterInternal();
  451. }
  452. private void DestroyInternal()
  453. {
  454. initialized = false;
  455. uuid = -1;
  456. if (spatializerApiImpl == SpatializerApiImpl.wwise)
  457. {
  458. PXR_Audio_Spatializer_Api.Destroy(context);
  459. context = IntPtr.Zero;
  460. return;
  461. }
  462. // Wait until all sources and listener's on-going audio DSP process had finished
  463. bool canContinue = true;
  464. do
  465. {
  466. canContinue = true;
  467. PXR_Audio_Spatializer_AudioListener[] listeners = FindObjectsOfType<PXR_Audio_Spatializer_AudioListener>();
  468. foreach (var listener in listeners)
  469. {
  470. if (listener != null && listener.IsAudioDSPInProgress)
  471. {
  472. canContinue = false;
  473. break;
  474. }
  475. }
  476. PXR_Audio_Spatializer_AudioSource[] sources = FindObjectsOfType<PXR_Audio_Spatializer_AudioSource>();
  477. foreach (var source in sources)
  478. {
  479. if (source != null && source.IsAudioDSPInProgress)
  480. {
  481. canContinue = false;
  482. break;
  483. }
  484. }
  485. } while (!canContinue);
  486. PXR_Audio_Spatializer_Api.Destroy(context);
  487. context = IntPtr.Zero;
  488. }
  489. private void OnDisable()
  490. {
  491. if (_instance != null && _instance == this)
  492. {
  493. _instance = null;
  494. // Remove context reset handler when destructing context
  495. // https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-add-an-event-handler?view=netdesktop-6.0
  496. AudioSettings.OnAudioConfigurationChanged -= OnAudioConfigurationChangedEventHandler;
  497. DestroyInternal();
  498. }
  499. }
  500. void Update()
  501. {
  502. if (isSceneDirty)
  503. {
  504. PXR_Audio_Spatializer_Api.CommitScene(context);
  505. isSceneDirty = false;
  506. }
  507. PXR_Audio_Spatializer_Api.UpdateScene(context);
  508. }
  509. void ResetContext(PXR_Audio.Spatializer.RenderingMode quality)
  510. {
  511. DestroyInternal();
  512. StartInternal(quality);
  513. if (spatializerApiImpl == SpatializerApiImpl.wwise)
  514. {
  515. return;
  516. }
  517. // Resume all sources playback
  518. var sources = FindObjectsOfType<PXR_Audio_Spatializer_AudioSource>();
  519. foreach (var source in sources)
  520. {
  521. source.Resume();
  522. }
  523. // Resume all ambisonic sources playback
  524. var ambisonicSources =
  525. FindObjectsOfType<PXR_Audio_Spatializer_AmbisonicSource>();
  526. foreach (var source in ambisonicSources)
  527. {
  528. source.Resume();
  529. }
  530. Debug.Log("Pico Spatializer Context restarted.");
  531. }
  532. }
粤ICP备19079148号