{"id":6076,"date":"2025-06-26T18:34:25","date_gmt":"2025-06-26T09:34:25","guid":{"rendered":"https:\/\/blog.criware.com\/?p=6076"},"modified":"2025-08-06T17:28:59","modified_gmt":"2025-08-06T08:28:59","slug":"adx-unity-synchronization-part-1","status":"publish","type":"post","link":"https:\/\/blog.criware.com\/index.php\/2025\/06\/26\/adx-unity-synchronization-part-1\/","title":{"rendered":"ADX &#038; Unity Synchronization [Part 1]"},"content":{"rendered":"<p>We recently learned how to synchronize a Unity scene with the content of a video played back by the Sofdec run-time, using the <a href=\"https:\/\/blog.criware.com\/index.php\/2025\/05\/27\/sofdec-cue-points\/\">cue points feature<\/a>. In this 2-part tutorial, we will see how we can synchronize a scene with the audio played back by ADX, to make it more realistic or more immersive. <\/p>\n<p><center><div style=\"width: 640px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-6076-1\" width=\"640\" height=\"360\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/video.mp4?_=1\" \/><a href=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/video.mp4\">https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/video.mp4<\/a><\/video><\/div><\/center><\/p>\n<p>In the scene depicted above, 2 synchronization mechanisms are used when the police knock on the door.<\/p>\n<p><strong>1 &#8211; Synchronization of a character\u2019s voice and subtitles<\/strong><br \/>\nThe random dialog line for the policeman is played every 3 seconds, and the corresponding subtitles are displayed. When the voice ends, the subtitles automatically disappear from the screen.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ResistanceIsFutile.png\" alt=\"\" width=\"368\" height=\"74\" class=\"alignnone size-full wp-image-6083\" srcset=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ResistanceIsFutile.png 737w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ResistanceIsFutile-300x60.png 300w\" sizes=\"auto, (max-width: 368px) 100vw, 368px\" \/><\/center><\/p>\n<p><strong>2 &#8211; Shaking based on audio events<\/strong><br \/>\nMarkers are placed in the Cue that implements the knocks on the door, and a callback is registered. The code will receive a notification during audio playback when the markers are reached, triggering the movement of the camera and the door.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ShakingTheDoor.png\" alt=\"\" width=\"651\" height=\"289\" class=\"alignnone size-full wp-image-6084\" srcset=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ShakingTheDoor.png 869w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ShakingTheDoor-300x133.png 300w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/ShakingTheDoor-768x341.png 768w\" sizes=\"auto, (max-width: 651px) 100vw, 651px\" \/><\/center><\/p>\n<p>In this post, we will focus on synchronizing the character\u2019s voice with the subtitles, and in the next one, we will implement the shaking based on the audio events.<br \/>\nTo synchronize the voice with the subtitles:<\/p>\n<p>1 &#8211; Create a Cue for each dialog line in AtomCraft and export the ACB file to Unity.<br \/>\n(The voice we used in the sample project was generated using this tool: https:\/\/ondoku3.com\/ja\/)<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Cues.png\" alt=\"\" width=\"639\" height=\"325\" class=\"alignnone size-full wp-image-6086\" srcset=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Cues.png 852w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Cues-300x153.png 300w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Cues-768x391.png 768w\" sizes=\"auto, (max-width: 639px) 100vw, 639px\" \/><\/center><\/p>\n<p>2 &#8211; Add the VoicePlayer (described below) script to an empty object, and assign multiple CRI Atom Sources to other objects, with the corresponding text in array format.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/VoicePlayer.png\" alt=\"\" width=\"973\" height=\"397\" class=\"alignnone size-full wp-image-6087\" srcset=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/VoicePlayer.png 1298w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/VoicePlayer-300x123.png 300w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/VoicePlayer-1024x419.png 1024w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/VoicePlayer-768x314.png 768w\" sizes=\"auto, (max-width: 973px) 100vw, 973px\" \/><\/center><\/p>\n<p>3 &#8211; Check the key points of the VoicePlayer script <\/p>\n<p><em>For voice and subtitles synchronization:<\/em><br \/>\nWe monitor the playback status (source.status) of the CriAtomSource and hide the subtitles when the voice ends.<\/p>\n<p><em>For random playback:<\/em><br \/>\nWe randomly select a dialog line using Random.Range(0, atomSources.Length).<\/p>\n<p><em>For subtitles display:<\/em><br \/>\nIf the previous subtitleCoroutine is running, we stop it (StopCoroutine) and execute ShowSubtitle().<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Script.png\" alt=\"\" width=\"933\" height=\"1142\" class=\"alignnone size-full wp-image-6088\" srcset=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Script.png 933w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Script-245x300.png 245w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Script-837x1024.png 837w, https:\/\/blog.criware.com\/wp-content\/uploads\/2025\/06\/Script-768x940.png 768w\" sizes=\"auto, (max-width: 933px) 100vw, 933px\" \/><\/center><\/p>\n<p>In addition to the method described this time, it is possible to store the dialog text and duration in AtomCraft markers and have Unity receive and display that information. However, for this first post, we deliberately introduced a simple script that is easy to implement for developers familiar with Unity, but not necessarily with ADX.<\/p>\n<p>Next time, we will use the Markers to shake the door and camera according to the timing of the door knocks.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We recently learned how to synchronize a Unity scene with the content of a video played back by the Sofdec<\/p>\n","protected":false},"author":2,"featured_media":6080,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[5,7,23],"tags":[],"class_list":["post-6076","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-adx","category-tutorials","category-unity"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/6076","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/comments?post=6076"}],"version-history":[{"count":19,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/6076\/revisions"}],"predecessor-version":[{"id":6102,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/6076\/revisions\/6102"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/media\/6080"}],"wp:attachment":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/media?parent=6076"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/categories?post=6076"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/tags?post=6076"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}