“Wwise는 스프레드시트(표 계산 소프트웨어) 같아요”. 이 말은 제가 사용자 환경팀으로서 자주 듣는 말입니다. 사실 Wwise는 사운드 디자인 도구이지만 사실 안을 들춰보면 Wwise 프로젝트는 데이터입니다. 정말 많은 데이터죠. 규모가 큰 현대 게임에서 문제를 방지하려면 데이터를 효과적으로 제어하는 것이 좋습니다.
다행히 Wwise는 List View, Multi Editor, Batch Rename, Query Editor와 같이 대량의 데이터를 조작할 수 있는 도구를 제공합니다.
또한 Wwise 프로젝트 안에는 대량의 데이터를 쉽게 다룰 수 있도록 구성을 개선하는 수많은 기술과 모범 사례가 있습니다. Work Unit 만들기, 명명 규칙 사용하기, 탭으로 구분된 파일로 오디오 파일 가져오기, 맞춤 속성 사용하기, 일괄 이름 변경 활용하기, 색깔 지정하기 등을 예로 들 수 있죠.
뿐만 아니라 Search 와 Query Editor는 특정 데이터를 찾을 수 있도록 도와줍니다. 하지만 이러한 도구에는 몇 가지 제약이 있습니다. 프로젝트에서 어떤 랜덤 컨테이너가 반복 재생 사운드를 사용하는지 찾으려는 경우엔 어떻게 할까요? Event가 참조하는 음원을 찾으려면요?
몇 년 전 오디오키네틱은, 프로그래머들에게 Wwise 프로젝트를 오토메이션(자동화), 조작, 쿼리할 수 있게 해주는 프로그래밍 API인 'WAAPI'를 소개했습니다. 하지만 WAAPI에서는 프로그래밍 언어를 사용해야 합니다. 따라서 대부분의 경우 프로그래머만 사용할 수 있어, 다른 Wwise 사용자는 접근하기가 힘들죠. 뿐만 아니라 WAAPI 스크립트를 제대로 작동하려면 어느 정도 구성 시간이 걸립니다.
다음은 Python(파이썬)으로 작성되었으며 Event에 의해 참조되는 변환된 모든 파일을 프린트하는 WAAPI의 예시입니다. 읽기가 그리 쉽지는 않죠.
from waapi import WaapiClient
import pprint
# 연결 (기본 URL)
client = WaapiClient()
# 모든 대상 반환
args = {
"from": {"path": ['\\Events\\Default Work Unit\\Play']},
"transform": [
{"select": ['children']}
]
}
options = {
"return": ['@Target']
}
result = client.call("ak.wwise.core.object.get", args, options=options)
pprint.pprint(result)
# 대상에서 모든 wem 파일 반환
args = {
"from": {"id": list(map(lambda x: x['@Target']['id'], result['return']))},
"transform": [
{"select": ['descendants']},
{"where": ['type:isIn', ['AudioFileSource']]}
]
}
options = {
"return": ['name', 'id','sound:convertedWemFilePath']
}
result = client.call("ak.wwise.core.object.get", args, options=options)
pprint.pprint(result)
# 연결 해제
client.disconnect()
WAQL 소개
Wwise 2021.1에서는 WAQL가 제공됩니다. WAQL은 Wwise Authoring Query Language(와이즈 저작 쿼리 언어)의 줄임말로, '와클'이라고 발음합니다. JIRA 사용자분들의 경우 JIRA Query Language (JQL, 지라 쿼리 언어)를 사용하여 JIRA 데이터베이스를 쿼리하는 방식을 아마 잘 아실 거예요. 프로그래머분들의 경우 C# LINQ, SQL을 잘 알고 계실 겁니다. WAQL은 이러한 언어와 비슷합니다. WAQL은 데이터 모델을 통해 Wwise 프로젝트를 쿼리하도록 해줍니다. 기본적으로 Wwise 오브젝트와 해당 속성을 쿼리하죠.
WAQL은 프로젝트 안에서 데이터를 더욱 쉽게 제어할 수 있도록 제공하는 다음 단계입니다. 새롭게 배워야 하는 언어라는 건 사실이지만, Python(파이썬), Javascript(자바스크립트), C#과 같은 완전한 프로그래밍 언어를 배우는 것보다 장벽이 훨씬 낮습니다. 무엇보다도 Wwise Authoring에서 바로 사용할 수 있죠. 이 글은 여러분이 WAQL의 기본 지식을 이해할 수 있도록 도와드리기 위해 작성되었습니다. 사실 이 글을 읽으면서 Wwise 프로젝트에서 직접 실행해보실 것을 권장해 드립니다. 이 글은 WAQL 튜토리얼 및 소개입니다.
자, 이제 간단한 것부터 시작해볼까요? 프로젝트에서 볼륨이 0보다 작은 모든 오브젝트를 찾아봅시다. 그렇게 하기 위해서 List View를 열고 $ where volume < 0을 입력하세요.
잠깐만요! 무슨 일이 벌어지고 있는지 이해해 봅시다. 먼저, List View 검색란에 입력할 경우 보통 전체 프로젝트에서 텍스트 검색을 실행하지만 이렇게 $부터 입력하기 시작할 경우 단순한 검색이 아니라 WAQL 쿼리를 실행하려고 한다는 것을 Wwise에게 알려줍니다.
다음으로 where이라는 키워드는 조건문을 작성하려고 함을 표시합니다. 기본적으로 where로 쿼리를 시작할 경우 프로젝트 내 모든 오브젝트에서 이 조건이 실행됩니다. 마지막으로 조건문을 작성합니다. 이 경우 Wwise 오브젝트의 속성인 볼륨 속성을 숫자인 0과 비교하려고 합니다. 이 조건은 볼륨이 0보다 작지 않은 모든 오브젝트를 필터링해냅니다.
Wwise 오브젝트와 속성
이제 다음 주제인 Wwise 오브젝트와 속성을 살펴봅시다. Wwise 오브젝트는 기본적으로 Project Explorer에 있는 모든 항목과 다른 시스템 안에 보이거나 숨겨져 있는 일부 오브젝트입니다. 속성은 오브젝트 안에서 정의되며 값을 저장합니다.
Wwise에는 수많은 속성이 있습니다. 예를 들어 다음은 Sound 오브젝트의 Property Editor에 있는 General Settings 탭에 있는 속성입니다.
속성은 다음 내용을 저장할 수 있습니다.
- 값 (정수, 실수, 불린, 문자열). 예: Volume(볼륨)
- 프로젝트에 있는 또 다른 오브젝트로의 참조. 예: OutputBus(출력 버스). Effect0
- 로컬 오브젝트. ‘Custom’이라고도 함. 예: Effect0
모든 Wwise 오브젝트에 대한 모든 속성의 전체 목록은 여기에서 확인할 수 있습니다.
뿐만 아니라 대부분의 오브젝트에서 찾을 수 있는 핵심 속성도 있습니다. 예를 들어 ‘name(이름)’, ‘notes(노트)’, ‘path(경로)’ ‘id(아이디)’는 모든 Wwise 오브젝트에서 접근할 수 있는 핵심 속성이지만 ‘volume’과 ‘outputbus’와 같은 속성은 특정 오브젝트에서만 찾을 수 있습니다. 핵심 속성은 경우에 따라 계산되기도 하고 오브젝트와 함께 저장되기도 합니다. WAQL에서 속성 이름은 모든 경우에서 항상 대소문자를 구별합니다.
핵심 속성에 대한 더 많은 정보는 여기를 참조해주세요.
조건 사용 시작하기
앞서 살펴본 것처럼 where 구문은 조건을 정의합니다. 이 조건은 where 구문이 주어진 모든 오브젝트에서 평가됩니다. 조건은 불린(boolean) 표현식으로 정의되며, true나 false가 될 수 있습니다.
다음은 몇 가지 예시입니다.
- $ where pitch = 1200
- $ where volume > -10 and volume < 0
- $ where IsLoopingEnabled or IsStreamingEnabled
- $ where (volume >= 0 and (lowpass > 0 or highpass > 0))
이제where조건을 사용해서 더 많은 상황을 실험해보세요.
또한 세 가지 문자열 비교 연산자 중 하나를 사용하면 WAQL로 텍스트를 검색 및 비교할 수 있습니다.
- $ where name = "Hello"
등호(=) 기호는 전체 문자열을 다른 문자열에 대해 대소문자를 구별하여 비교하는 데에 사용되며, 문자열이 완전히 같을 경우 true를 반환합니다. - $ where notes : "hell"
콜론(:) 기호는 문자열에서 시작하는 단어를 찾는 데에 사용됩니다. 이 구분자는 대소문자를 구별합니다. 찾아낸 단어가 있을 경우 true를 반환합니다. - $ where outputbus = /^Music\d+$/
또한 등호 연산자는 정규식 표현(ECMAScript 스타일)과도 사용할 수 있습니다.
오브젝트와 속성 변경하기
Wwise 오브젝트에는 두 가지 유형의 속성이 있습니다:
값을 반환하는 속성:
- volume, pitch, lowpass(저대역 통과) 등: 보통 Wwise에서 슬라이더와 연결되며 숫자를 저장합니다. 이러한 속성은 오브젝트의 유형마다 다릅니다. 예를 들어 Sound와 Random Container는 서로 다른 속성 세트를 갖습니다.
- name, notes, id, path: Wwise 오브젝트 시스템의 핵심 구성 요소이며, 종종 문자열 값을 저장합니다. 이러한 속성은 모든 Wwise 오브젝트에서 찾을 수 있습니다.
또 다른 Wwise 오브젝트를 반환하는 속성 (참조라고도 함):
- outputbus, target, userauxsend0, effect0: 이 속성은 다른 오브젝트를 가리키며, 오브젝트의 유형마다 다릅니다. 예를 들어 Event와 Sound는 서로 다른 속성을 갖습니다.
- parent(상위 계층): 상위 오브젝트를 가리킵니다.
마침표(.) 기호를 사용하면 오브젝트와 값을 조합할 수 있습니다. 예:
- $ where parent.name = "Music"
상위 계층의 이름이 'Music'입니다. - $ where parent.parent.name = "Music"
상위 계층의 상위 계층이 'Music'입니다. - $ where parent.volume < 0
상위 계층의 볼륨이 0보다 작습니다. - $ where outputbus.parent.name = "Master Audio Bus"
출력 버스의 상위 계층 이름이 'Master Audio Bus'입니다. - $ where effect0.pluginname = "Wwise Compressor"
슬롯 0에 있는 효과의 플러그인 이름이 'Wwise Compressor'입니다.
다른 근원에서부터 시작하기
이제까지는 전체 프로젝트에서 프로젝트를 필터링해왔습니다. 하지만 경우에 따라 보다 좁은 범위의 오브젝트를 집중적으로 검색해볼 수 있습니다. WAQL은 쿼리의 근원을 다음으로 설정할 수 있게 해줍니다:
- 지정된 유형의 모든 오브젝트
- 프로젝트에서 한 개 이상의 특정 오브젝트
- 레거시 쿼리 오브젝트의 결과 (Query Editor)
- 텍스트 검색 쿼리의 결과
다음은 몇 가지 예시입니다:
- $ from type sound
- $ from type audiofilesource
- $ from type randomsequencecontainer, switchcontainer, blendcontainer
from 구문에서 유형을 직접 지정하면 검색의 범위를 아주 효율적으로 좁힐 수 있습니다. WAQL는 지정된 근원에 한해 반복 작업을 진행합니다. 또한 마지막 쿼리는 where 키워드를 사용하여 필터 검색으로 작성할 수 있습니다. 하지만 이 필터링은 Event, 버스, 사운드 등 모든 프로젝트 오브젝트를 거쳐야 합니다. 그렇기 때문에 실행 시간이 더 길어질 수 있습니다:
- $ where type = "randomsequencecontainer" or type = "switchcontainer" or type = "blendcontainer"
다른 오브젝트 유형으로 시도해보세요. 여기를 참조하세요.
또한 한 오브젝트에서 시작하는 것이 아주 편리할 수 있습니다.
- $ from object "\Actor-Mixer Hierarchy\Default Work Unit"
- $ from object "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ from object "Event:Play_Footstep_01"7
이전 쿼리는 또한 from object를 생락하여 보다 짧은 형식으로 작성할 수 있습니다.
- $ "\Actor-Mixer Hierarchy\Default Work Unit"
- $ "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ "Event:Play_Footstep_01"
뿐만 아니라 여러 오브젝트를 지정할 수도 있습니다.
- $ "\Actor-Mixer Hierarchy", "\Interactive Music Hierarchy"
- $ "{DE2B0843-131F-4E52-BC71-23C43A5324AB}", "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ "Event:Play_Footstep_01", "Event:Play_Footstep_02", "Event:Play_Footstep_03"
다음은 여러 다른 근원을 시작점으로 사용하는 쿼리의 예시입니다.
- $ from search "foot walk"
- $ from search "hello" where type = "sound"
- $ from query "\Queries\Factory Queries\Audio Source\Audio Source - Format = Vorbis"
오브젝트 선택하기
이제까지 from 키워드로 WAQL의 근원을 지정하고 where 키워드를 사용하여 WAQL 쿼리를 필터링하는 법을 살펴보았습니다. 이제 select 키워드를 사용하여 결과를 더 변형할 수 있는 법을 살펴볼까요?
오브젝트를 선택하면 초기 오브젝트 시퀀스로부터 다른 오브젝트를 가져올 수 있게 해줍니다. WAQL 쿼리의 각 부분이 다음 부분을 제공한다는 것을 잊지 마세요.
List View에서 다음 쿼리를 입력하세요:
- $ from object "\Actor-Mixer Hierarchy\Default Work Unit" select children
이 쿼리는 Default Work Unit에서 직접적인 모든 하위 계층을 반환합니다. 이 쿼리에는 from 구문과 select 구문이라는 두 가지 부분이 있습니다. from 구문은 쿼리의 시작 부분, 다시 말해 근원을 정의합니다. select 구문은 근원으로부터 오는 모든 오브젝트에서 실행됩니다.
다음은 오브젝트 계층 구조에서 서로 다른 구성 요소를 선택하는 다른 쿼리입니다:
- $ "\Actor-Mixer Hierarchy\Default Work Unit" select descendants
모든 하위 계층을 재귀적으로 반환합니다. - $ "\Actor-Mixer Hierarchy\Default Work Unit" select parent
직접적인 하위 계층을 반환합니다.
$ "\Actor-Mixer Hierarchy\Default Work Unit" select parent.parent
직접적인 상위 계층의 상위 계층을 반환합니다. - $ "\Actor-Mixer Hierarchy\Default Work Unit" select ancestors
모든 상위 계층을 재귀적으로 반환합니다. - $ "\Actor-Mixer Hierarchy\Default Work Unit" select parent, children
상위 계층을 하위 계층과 함께 묶어 반환합니다. - $ "\Actor-Mixer Hierarchy\Default Work Unit" select this, parent, children
Default Work Unit 자체, 이 작업 단위의 상위 계층과 하위 계층을 묶어 반환합니다. - $ from type sound select parent
모든 사운드의 모든 상위 계층을 반환합니다.
select 키워드를 사용하면 계층 구조의 하위 및 상위 계층을 탐색할 뿐만 아니라 속성으로부터 오브젝트를 선택할 수도 있습니다:
- $ from type sound select effect0
모든 사운드 오브젝트의 색인 0에 있는 모든 효과를 반환합니다. - $ from type sound select effect0, effect1, effect2, effect3
모든 사운드 오브젝트에서 찾은 모든 효과를 반환합니다. - $ from type sound select outputbus
모든 사운드 오브젝트의 Output Bus에 있는 모든 버스를 반환합니다. - $ from type sound select outputbus.parent
모든 사운드 오브젝트의 Output Bus에 있는 버스의 상위 계층을 반환합니다.
추가 실습:
- select 구문 뒤에 where 구문을 추가해보세요.
- select 구문 전에 where 구문을 삽입해보세요.
- select referencesto를 사용해보세요
복잡한 쿼리 분석하기
다음 쿼리를 분석해봅시다. 이 쿼리는 Event에 의해 참조되는 모든 Sound 오브젝트를 열거합니다. 이 쿼리에는 다섯 개의 구문이 서로 연결되어 있습니다:
- $ from type event select children select target select this, descendants where type = "sound"
쿼리의 각 부분은 다음과 같습니다:
- $ from type event
프로젝트의 모든 Event를 먼저 열거하는 것으로 시작합니다 - $ from type event select children
그런 다음 Event 오브젝트로부터 Event 동작(직접적인 하위 계층)을 가져옵니다. - $ from type event select children select target
그런 다음 각 동작의 대상 (참조와 지명된 대상)을 가져옵니다. - $ from type event select children select target select this, descendants
그 후 대상 자체(this 키워드를 사용해서)와 이 대상의 하위 계층을 가져옵니다. - $ from type event select children select target select this, descendants where type = "sound"
마지막으로 사운드 오브젝트만 유지합니다.
이제 무엇을 해볼까요?
여기서 다룬 내용은 단지 빙산의 일각에 불과합니다. 현재 WAQL의 버전 1이 제공되지만 계속해서 새로운 버전이 나올 예정입니다. 벌써 450개의 서로 다른 속성에 접근하고 60개의 서로 다른 오브젝트 유형을 쿼리할 수 있습니다. 원하는대로 수많은 구문을 순서에 상관 없이 조합해보세요. 이 언어가 제공해주는 가능성은 지금도 거의 무한합니다. 또한 이 글에서 언급하지 않은 다른 키워드도 있습니다.
List View에서 WAQL 사용하기를 연습해보세요. 또한 Query Editor를 사용해서 프로젝트에 있는 WAQL 쿼리를 저장해보세요.
WAQL과 이 언어가 지원하는 모든 내용에 대해 더 알아보시려면 WAQL 참조를 참고해주세요.
WAAPI 사용자분들의 경우 ak.wwise.core.object.get 함수 안에서 WAQL을 직접 사용할 수도 있습니다. 여러분의 삶이 훨씬 편해질 거예요.
WAQL로 어떤 것을 할 수 있었는지 저희에게 알려주세요!
댓글