WAQL 2.0

오디오 프로그래밍 / Wwise에 대한 팁과 도구

Wwise Authoring Query Language (WAQL, 와클) 첫 번째 버전이 출시된 지 벌써 몇 년이 지났습니다. 첫 버전 이후 크게 변경된 점은 없습니다. 가장 눈에 띄는 변화로는 Wwise 2022.1의 Project Explorer Search에 WAQL이 통합되었다는 부분이었죠. 이 블로그에서 곧 출시될 2023.1 출시와 더불어 쿼리 언어를 한 단계 높은 수준으로 끌어올리는 방법에 대해 다뤄보겠습니다.

먼저 WAQL이 무엇인지 알아보려면 다음 블로그를 읽어보세요. https://blog.audiokinetic.com/ko/introducing-waql/

자세한 내용을 다루기 전에 Wwise Authoring 2023.1 업데이트 작업 중 일부를 요약해 보겠습니다. 지난 몇 년 동안 Wwise Authoring (Wwise 저작)의 가장 오래된 데이터 모델 중 일부를 일반 객체 모델(generic object model)로 변환했습니다. 그러면 기본적으로 Wwise의 모든 객체를 동일한 방식으로 처리할 수 있게 됩니다. 예를 들어 각 객체에는 볼륨(volume) 같은 속성이나 출력 버스(output bus)와 같은 다른 객체에 대한 참조가 있습니다. 이를 이용하면 특정한 함수를 만들 필요 없이 WAQL이나 WAAPI에 일반적인 모든 것을 노출할 수 있죠. 이를테면 WAAPI에는 setVolume 함수가 없습니다. 그래서 볼륨을 설정하려면 ak.wwise.core.object.setProperty 또는 ak.wwise.core.object.set을 호출하고 속성 이름으로 'volume'을 전달하면 됩니다.

객체 목록의 개념(concept of object lists) 이라는, 다소 새로운 부분이 추가되었는데요. 이 객체 목록을 사용하면 모든 객체 내부에 있는 가변 수의 객체나 객체에 대한 참조를 저장할 수 있습니다. 예를 들어 Actor-Mixer Hierarchy의 각 객체에는 이제 RTPC 객체 목록과 Effect Slots 목록이 존재합니다. 이는 볼륨을 설정할 때와 마찬가지로 ak.wwise.core.object.set
로 RTPC 객체나 효과를 설정할 수 있습니다.
효과와 WAQL에 대해 더 자세히 알아볼까요. 2022.1 이하 버전에서 0번 슬롯에 EQ가 있는 모든 객체를 쿼리하려면 다음을 수행하면 됩니다.

$ where effect0.pluginname : "EQ"

이렇게 하면 첫 번째 효과의 플러그인 이름에 'EQ'가 포함된 프로젝트의 모든 객체가 반환됩니다. 흠, 효과 슬롯의 경우에는 쿼리가 좀 덜 깔끔해 보이네요.

$ where effect0.pluginname : "EQ" or effect1.pluginname : "EQ" or effect2.pluginname : "EQ" or effect3.pluginname : "EQ"

또한 2023.1에서는 이렇게 4개로 고정된 효과 슬롯을 제거하고 객체 목록으로 대체합니다. WAQL을 사용해서 어떻게 객체 목록의 효과를 쿼리할 수 있는 지 알아볼까요? 이전에는 WAQL에서 객체 목록에 대한 지원을 적절히 추가해야 했습니다.

List 함수 소개

WAQL에서 where statement, select문(statement)이나 반환 식(return expression) 안에서 사용할 수 있는 다양한 접근자의 타입이 다를 수 있습니다. 타입 목록.

Accessor 타입

반환

예시

Property (속성)

Variant (integer, float, boolean, string).

Volume, Pitch, IsLoopingEnabled

Reference (참조)

Wwise Object

Output Bus, User Aux Send 0, Attenuation

Object List (객체 목록) - 신규!

Wwise Object의 배열

RTPC, Effects, children, descendants

JSON 객체

키 값이 있는 JSON 객체.

duration.max, duration.min, loudness.integrated

객체 목록은 이제 WAQL에서 기본적으로 지원되며 이를 이용해서 할 수 있는 작업이 몇 가지 있습니다. 그 중 새롭게 추가된 하나는 목록에 있는 모든 요소에 한 번에 작동하는 함수입니다.

count() 함수부터 살펴보겠습니다. count() 함수는 목록의 요소 개수를 반환합니다. 이 숫자는 다른 숫자와 비교할 수 있습니다. 예제:

$ where effects.count() > 0

매우 유용한 이 작업과 함께, count() 함수는 선택적 조건을 인자로 사용할 수도 있습니다. 따라서 특정 조건과 일치하는 요소의 수를 셀 수도 있죠. 효과 목록에서 EQ가 있는 객체를 검색해 보겠습니다.

$ where effects.count(effect.pluginname : "eq") > 0

하나의 요소가 조건을 충족하는 즉시 true를 반환하는 any() 함수로 이 쿼리를 작성할 수도 있습니다. 그러면 더 효과적이겠죠.

$ where effects.any(effect.pluginname : "eq")

목록에서 사용할 수 있는 함수는 다음과 같습니다.

함수

설명

예시

count

조건과 일치하는 목록의 요소 수를 반환하고 그렇지 않으면 false를 반환합니다. 조건문은 선택적으로 사용할 수 있습니다.

$ where children.count() > 3
$ where effects.count(effect.pluginname:"eq") > 0

any

조건과 일치하는 요소가 발견되면 true를 반환하고 그렇지 않으면 false를 반환합니다. 비어 있으면 false를 반환합니다. 조건문은 선택적으로 사용할 수 있습니다.

$ where rtpc.any()
$ where children.any(type = "Sound")

all

목록의 모든 요소가 해당 조건과 일치하면 true를 반환하고 그렇지 않으면 false를 반환합니다. 비어 있으면 false를 반환합니다. 여기서 조건문은 필수입니다.

$ where children.all(type = "Sound")

first

해당 조건과 일치하는 첫 번째 요소를 반환합니다. 조건문은 선택적으로 사용할 수 있습니다.

$ where effects.first(effect.pluginname :"EQ") != null
$ where children.first().type = "Sound"

last

해당 조건과 일치하는 마지막 요소를 반환합니다. 조건문은 선택적으로 사용할 수 있습니다.

$ where effects.last(effect.pluginname :"EQ") != null
$ where children.last().type = "Sound"

take

특정 개수의 요소를 가져와서 새 목록에 반환합니다. 

$ select children.take(2)

skip

특정 개수의 요소를 건너뛰고 나머지 요소를 새 목록으로 반환합니다. 

$ select effects.skip(1)

at

목록의 지정된 인덱스에 있는 요소를 반환합니다.

$ select effects.at(0)

where

새 목록에서 해당 조건과 일치하는 요소를 반환합니다.

$ select effects.where(effect.pluginname :"EQ")

효과와 관련하여 더 알아보기

이제 효과에 대해 좀 더 이야기해 볼까요? 2023.1에서 Sound Engine 단에서 최대 효과의 수가 4개에서 255개로 늘어났습니다. 그러나 Wwise Authoring에서는 그 수에 제한이 없습니다 (특정 시점에서 메모리와 같은 시스템 리소스는 제외). 그래서 효과를 목록에 보관해야 하는것이죠. 다음은 Sound 객체의 효과에 대한 데이터 모델의 UML 다이어그램입니다.

img1

또한 EffectSlot이라는 새로운 객체 유형이 나왔습니다. EffectSlot은 BypassRender 속성을 저장하고 ShareSet이나 Custom 효과에 대한 Effect 참조를 저장하는 작은 객체입니다.

Sound 오브젝트는 EffectSlot 객체 목록을 저장하고 Sound에 대한 모든 효과를 한 번에 바이패스하는 BypassEffects 속성도 저장합니다.

아래처럼 실제 프로젝트의 모든 EffectSlot 객체를 쿼리할 수 있죠.

$ from type effectslot

Return Expression의 더 강력한 기능

WAAPI와 함께 WAQL을 사용하면 반환 표현식을 사용해서 반환된 객체에 대해 특정 데이터를 쿼리할 수 있습니다. 예를 들어 프로젝트에서 모든 Sound 오브젝트를 반환하는 다음과 같은 WAQL 쿼리를 사용할 수 있습니다.

$ from type sound

반환 표현식의 JSON 배열 사용.

["name", "volume"]

다음 표를 JSON 형식으로 반환하게 됩니다.

이름

볼륨

Silence

0

Ambient_Day_Element_01_01

0

Ambient_Day_Element_01_02

0

waterdrop_05

-4

Ambient_Water_River

-20

이제 해당 사운드에 대한 RTPC를 얻으려고 한다고 가정해 보죠. Wwise 2022.1에서 가능했던 다음과 같은 표현식을 사용할 수 있습니다.

["name", "volume", "rtpc"]

하지만 이렇게 하면 rtpc 열의 경우 각 행에 대해 다음과 같은 결과가 나타납니다.

[
  {
    "id": "{1D1905C4-18F9-4506-AD8B-A0CDEC396F4D}"
  }
]

이는 JSON 객체의 배열로, 각 객체에는 RTPC 항목의 ID가 포함되어 있습니다. 해당 GUID에 대해 이미 알고 있거나 GUID에 대해 더 알아보기 위해 추가적인 쿼리를 수행하는 경우에만 유용합니다. 기본적으로 WAQL은 Wwise 객체를 반환할 때 객체의 ID와 이름을 반환합니다. 이 경우 RTPC 객체에는 이름이 없기 때문에 ID만 반환되죠.

RTPC가 연결된 속성 이름과 RTPC를 제어하는 입력 이름을 얻으려고 한다고 가정해 볼까요? 2023.1에는 컴포지션별로 새 JSON 객체를 반환할 수 있는 새로운 구문이 존재합니다.

["name", "volume", "rtpc.{controlinput, propertyname}"]

마지막 열에 대해 다음과 같이 반환합니다.

[
  {
    "controlinput": {
      "id": "{CEC3FD56-5B7C-44AF-B635-5C3A0C36825E}",
      "name": "Distance_to_Camera"
    },
    "propertyname": "Volume"
  }
]

ControlInput 참조에 대한 idname을 모두 가져오는 것을 다시 볼 수 있습니다. 기본값으로 되어있네요. 제어 입력(control input)의 ID가 필요 없는 경우 다음과 같은 식의 배열을 사용할 수 있습니다.

["name", "volume", "rtpc.{controlinput.name, propertyname}"]

그러면 다음처럼 더 간결하고 명쾌한 결과를 얻을 수 있습니다.

[
  {
    "controlinput.name": "Distance_to_Camera",
    "propertyname": "Volume"
  }
]

이제 문제는 이 열에 접근하는 데 필요한 코드가 JSON 객체의 키로 매우 장황한 반환식을 사용한다는 것입니다. 예를 들어 요청한 RTPC 입력란에 액세스하려면 첫 번째 행에서 다음과 같은 Python 코드가 필요합니다.

myRTPCs = results[0]['rtpc.{controlinput.name, propertyname}']

이 문제를 완화하기 위해서 키워드 as를 사용하여 별칭 개념(concept of aliases) 도입으로 식의 이름을 바꿀 수 있도록 하겠습니다.

["name", "volume", "rtpc.{controlinput.name, propertyname} as rtpcs"]

이렇게 더 간략해진 코드는 다음과 같이 나타납니다.

myRTPCs = results[0]['rtpcs']

목록 연결 (Concatenation of Lists)

마지막으로 소개할 내용는 목록 연결입니다. 예를 들어 프로젝트에서 모든 이벤트를 가져온다고 가정해봅시다.

$ from type event

다음은 각 개별 이벤트와 관련된 모든 원본 WAV 파일을 가져올 수 있는 마법의 표현입니다.

["name as event", "children.target.[this, descendants].where(type=\"Sound\").originalRelativeFilePath as originals"]

결과:

이벤트

원본

Ambient_Region_PineForest

[
"SFX\\Ambient\\Ambient_Background\\treesVillage_001.wav",
"SFX\\Ambient\\Ambient_Background\\treesVillage_001.wav",
"SFX\\Ambient\\Ambient_Background\\BAS_amb_pineforest_night_background_loop_01.wav",
"SFX\\Ambient\\Ambient_Background\\BAS_amb_pineforest_night_background_loop_01.wav"
]

Ambient_River

[
"SFX\\Ambient\\Ambient_Emitters\\Water_RiverLoop.wav"
]

정확히 어떠한 일이 일어나고 있을까요? 여기에는 많은 개념이 숨어 있습니다. 표현을 분석해 보겠습니다.

children

actions인 이벤트의 하위 목록을 반환합니다. 

.target

각 작업의 target 객체를 선택합니다. 이것은 일반적으로 Actor-Mixer Hierarchy의 객체를 말합니다.

.[this, descendants]

각 대상의 대상 자체(this)와 해당 descendant의 연결(concatenation)인 새로운 배열을 빌드하고 선택합니다.

.where(type=\"Sound\")

Sound 객체만 유지해서 객체를 필터링합니다. JSON 값 안에 있기 때문에 큰따옴표를 이스케이프했음을 참고하세요.

.originalRelativeFilePath

각 Sound의 Originals 폴더에 상대적인 원본 WAV 파일 경로를 선택합니다.

기타 목록

WAQL에서 사용할 수 있는 목록은 다음과 같습니다.

특정 목록:

  • 많은 객체의 Effects (신규!)
  • 많은 객체의 RTPC
  • Random/Sequence Container의 Playlists (신규!)
  • Audio File Source의 Markers (신규!)
  • Actor-Mixer Hierarchy 객체의 Metadata
  • Music Switch Container의 Entries, Arguments (신규!)
  • Dialog Event의 Entries, Arguments (신규!)
  • Music 객체의 Stingers
  • Music Segment의 Cues
  • Music Track의 Sequences
  • Music Sequence의 Clips (서브트랙)

일반 목록:

  • children
  • ancestors
  • descendants
  • referencesTo

글을 마치며.

정말 많은 것들을 다루었네요. 이 블로그 내용과 관련해서 더 자세히 알아보고 직접 사용해 보고싶다면 WAQL Playground(https://github.com/ak-brodrigue/waql-playground)를 참고해 주세요. 여기서 보여드린 많은 기능들을 확인할 수 있습니다. Wwise 2023.1을 다운로드하고 프로젝트에 직접 사용해 보세요. 새로운 기능을 배우고 이해할 때 직접 사용해 보는 것보다 더 좋은 방법은 없답니다.

WAQL의 기본 방향은 데이터에 대한 제어와 가시성을 제공하는 것입니다. 그리고 이러한 새로운 기능은 아이디어를 더욱 발전시키죠.

Project Explorer 검색, List View 검색, Schematic View, Toolbar 검색, Query Editor에서 직접 WAQL을 사용할 수 있다는 점을 기억해주세요.

또한 WAQL Reference (https://www.audiokinetic.com/ko/library/edge/?source=SDK&id=waql_reference.html)와 Wwise 오브젝트 레퍼런스 (https://www.audiokinetic.com/ko/library/edge/?source=SDK&id=wobjects_index.html)는 WAQL과 객체 모델의 숨겨진 보석을 발견하는 데 항상 유용합니다.

베르나르 로드리그 (Bernard Rodrigue)

베르나르 로드리그 (Bernard Rodrigue)

Audiokinetic개발 감독Bernard Rodrigue는 Audiokinetic의 개발 감독입니다. Bernard는 2005년 Audiokinetic에 입사했으며 Wwise의 기초를 개발하는 데 큰 공헌을 했습니다. 현재 Bernard는 계속해서 Wwise의 발전과 확장에 관한 여러 프로젝트를 이끌어 나가고 있습니다.

 @decasteljau

댓글

댓글 달기

이메일 주소는 공개되지 않습니다.

다른 글

Wwise 개발팀이 직접 전해드리는 팁!

이 글은 주로 Wwise 고급 사용자에 초점을 맞춰, 몇 가지 팁을 통해 비교적 덜 알려진 Wwise 기능을 다루고 있습니다. 여러분의 지식 수준에 따라 일부 섹션은...

30.4.2019 - 작성자: 베르나르 로드리그 (Bernard Rodrigue)

Wwise와 REAPER의 연결: Part 2 - ReaOpen

ReaOpen은 오디오 파일을 선택하고 원래의 REAPER 프로젝트를 쉽게 열 수 있는 무료의 가벼운 프로그램입니다. Windows와 Mac 모두에서 실행되며 Wwise,...

7.4.2020 - 작성자: 니콜라 루키치 (NIKOLA LUKIĆ)

누구나 사용할 수 있는 WAAPI - 제 1부: 개요

안녕하세요. 저는 왕양 (汪洋) 이라고 합니다 (혹은 ‘씨 예’, 溪夜라고도 불립니다). 저는 작년 하반기에 WAAPI에 대해 알게 되었습니다 (Wwise 저작 API). 저같이...

30.3.2021 - 작성자: 토마스 왕 (THOMAS WANG, 汪洋)

Impacter와 Unreal - 게임 물리를 사용하여 Impacter 플러그인 제어하기

소개 Impacter(임팩터)는 Wwise를 위한 새로운 타격음 모델링 플러그인입니다. 플러그인 소개는 이 글을 통해 확인해주세요. 이 글에서는 Impacter를 사용하여...

3.6.2021 - 작성자: 션 소라한 (Sean Soraghan)

Wwise+GME 게임 음성 솔루션: 다양한 음성 플레이 대방출, 생생한 몰입감 선사

AppAnnie2021 모바일 게임 리포트는 강력한 소셜 인터랙션 속성을 가진 배틀 그라운드, 슈팅 및 온라인 MOBA가 플레이어들의 사랑을 많이 받았으며 게임 시간 증가를...

13.1.2022 - 작성자: Tencent Cloud

대사 | Wwise와 Unity에서의 나레이션

현대 게임의 필수 요소 중 하나인 보이스오버 대사는 플레이어가 캐릭터를 특정 목소리와 연관지을 수 있을 뿐만 아니라 전반적인 억양을 통해 캐릭터의 감정을 더 잘 이해할 수 있게...

5.4.2023 - 작성자: Jake Gamelin (제이크 겜린)

다른 글

Wwise 개발팀이 직접 전해드리는 팁!

이 글은 주로 Wwise 고급 사용자에 초점을 맞춰, 몇 가지 팁을 통해 비교적 덜 알려진 Wwise 기능을 다루고 있습니다. 여러분의 지식 수준에 따라 일부 섹션은...

Wwise와 REAPER의 연결: Part 2 - ReaOpen

ReaOpen은 오디오 파일을 선택하고 원래의 REAPER 프로젝트를 쉽게 열 수 있는 무료의 가벼운 프로그램입니다. Windows와 Mac 모두에서 실행되며 Wwise,...

누구나 사용할 수 있는 WAAPI - 제 1부: 개요

안녕하세요. 저는 왕양 (汪洋) 이라고 합니다 (혹은 ‘씨 예’, 溪夜라고도 불립니다). 저는 작년 하반기에 WAAPI에 대해 알게 되었습니다 (Wwise 저작 API). 저같이...