ReaWwise 개발 | 제 2부 - 구현

Wwise에 대한 팁과 도구

이 글은 2부작으로 제작된 블로그 시리즈의 제 2부입니다. 제 1부에서는 ReaWwise의 사전 제작에 대해 알아보았고, 제 2부에서는 이 확장의 개발에 대해 알아보게 됩니다.

거의 최종에 가까운 사용자 인터페이스 디자인과 WAAPI-Transfer 코드 베이스에 대한 가정을 검증하기 위한 여러 반복 작업을 걸친 후 이제 프로젝트의 기술적인 기반에 대한 몇 가지 결정을 내려야 할 때가 왔습니다.

프로그래밍 언어

REAPER는 스크립트 제작을 위한 여러 프로그래밍 언어를 지원합니다 (Lua, EEL, Python, C++). 다른 언어를 제치고 C++가 선택된 이유는 여러가지가 있습니다.

  • Audiokinetic 팀이 제공하는 C++ 전문성
  • 기존 코드 재사용
    • WAAPI C++ 클라이언트
  • REAPER의 Lua처럼 REAPER와 결합된 언어에 의존하지 않음
  • Python 스크립트의 인터프리터같이 런타임 종속성에 의존하지 않음
  • WAAPI-Transfer와 같은 기타 오픈 소스 프로젝트의 재사용 잠재성
  • GUI에 대해 있을 수 있는 기타 ReaScript에 대한 의존성이 없음

프레임워크

사용할 언어를 설정한 후 이제 프로젝트에 어떤 프레임워크가 가장 적절한지를 살펴봐야 했습니다. 이를 결정하기 위해 다음 기준을 사용했습니다.

  • 크로스 플랫폼이어야 함 (Windows와 Mac)
  • 탄탄한 커뮤니티 지원이 있어야 함
  • 테마 설정과 커스터마이징이 완전히 가능해야 함
  • 현대 프로그래밍 패턴 및 패러다임을 사용해야 함
  • 회사의 코딩 표준과 잘 맞아야 함

WDL/Native

C++ 기반 REAPER 확장에는 이 방법을 가장 많이 사용하는 것 같습니다. OS에서 호스트하는 창의 맥락 내에서 사용자 인터페이스를 제작할 수 있죠. 또한 Mac에서 Win32 API의 부분 집합을 사용할 수 있게 해주는 SWELL도 제공합니다. 이는 크로스 플랫폼 호환성에서 중요합니다. 

개발 초기 단계 동안 저희는 WAAPI-Transfer 코드 베이스를 사용하여 특정 아이디어를 검토했습니다. 그리고 SWELL에서 지원하지 않는 Win32 API 사용이 꽤 많다는 것을 깨달았죠. 이는 교차 플랫폼 호환성에서 몇 가지 문제를 일으켰고 특정 그래픽 컴포넌트를 사용할 수 없음을 의미했습니다.

SWELL의 경우 Mac에서 네이티브 컴포넌트를 사용할 시 Mac과 Windows에서의 모습과 경험이 완전히 동일하지 않음을 의미했죠. 

Win32 API를 사용할 경우 또 다른 단점은 어렵기로 소문난 API입니다. C 언어로 제작되었고 수년간 존재해온 API이죠. 또한 이전 버전과의 호환성을 유지해야 한다는 요구 사항은 많은 레거시 아티팩트가 여전히 많이 남아있다는 것을 의미합니다.

JUCE

JUCE는 오디오 관련 애플리케이션과 플러그인을 생성하는 데 흔히 사용되는 크로스 플랫폼 C++ 프레임워크입니다. 현대적이며 안정적인 API를 가지고 있으며, 커스터마이징 가능성이 뛰어나고, 커뮤니티 지원도 탄탄합니다. 또한 CMake에 대한 네이티브 지원도 있습니다. 이에 대해서는 글의 후반부에서 더 다루도록 하겠습니다. 

저는 오픈 소스의 JUCE 기반 REAPER 확장을 아직 본 적이 없습니다. 하지만 REAPER 확장에서의 JUCE 구현이 충분히 가능하며 꽤나 간단한 일이라는 것을 알려주는 코드 몇 조각을 발견했죠!

WAAPI-Transfer 코드 베이스에서 어느 정도 작업을 한 후 새로운 UX가 꽤나 달랐기 때문에 대부분의 UI를 다시 제작해야 한다는 것이 분명해졌습니다. JUCE 컴포넌트의 도면을 쉽게 접근하고 재정의할 수 있기 때문에 바닐라 JUCE 컴포넌트를 계획한 디자인 그대로 정확하게 보이도록 만드는 것이 쉬웠습니다.

이벤트 처리 시스템도 Win32 이벤트 처리 시스템을 직접 사용하는 것보다 훨씬 더 직관적입니다. 이벤트가 컴포넌트 자체 안에서 관리되죠. 창의 메시지 반복 재생 복잡성이 JUCE에 의해 추상화되기 때문에 따로 관리할 필요가 없습니다.

JUCE의 또 다른 장점은 오브젝트 지향 프로그래밍 자체가 GUI 애플리케이션 개발에 적합하다는 것입니다. 서로 다른 GUI 컴포넌트를 오브젝트로서 쉽게 표시할 수 있고 각 오브젝트가 함수의 형태로서 기능을 보여줄 수 있죠. Win32 API의 경우 이 부분이 자연스럽게 실행되지 않습니다. 컴포넌트는 구조체로 정의됩니다. JUCE를 사용할 경우와 동일한 방식으로 코드를 구성하려면 더 많은 주의가 필요합니다.

프로젝트 구성 및 구조

프로젝트 구조를 살펴보기 전에 먼저 CMake를 소개해드릴게요.

CMake

ReaWwise 프로젝트는 빌드 파일을 담고 있지 않습니다. 대신 CMake를 사용합니다. CMake는 프로젝트가 어떻게 빌드되어야 하는지를 일반적인 방식으로 설명할 수 있게 해줍니다. 그 후 CMake를 사용하여 플랫폼 전용 빌드 파일을 생성할 수 있습니다.

CMake를 사용하면 몇 가지 장점이 있습니다.

  • 각 빌드 환경마다 서로 다른 빌드 파일을 관리할 필요가 없음
  • 시스템 라이브러리를 찾는 도우미 함수가 있음
  • 광범위한 시스템의 빌드 파일을 생성할 수 있음
  • 파일 저작 및 쉘 명령 실행 등 추가 업무를 실행할 수 있음.

프로젝트 구조

처음부터 걱정이 될 수 있는 것들을 최대한 분리하는 것이 의도였습니다. 그래서 코드 베이스를 다음 네 개의 메인 프로젝트로 구성했죠.  

ReaWwise (src/extension)

이 프로젝트는 모든 REAPER 전용 코드를 담고 있습니다. 이는 확장 엔트리 포인트를 정의하고 확장 API에 필요한 모든 호출을 수행합니다. 또한 다른 확장에 사용할 수 있도록 WAAPI를 Lua에 노출시키는 코드를 담습니다. 이 프로젝트는 공유 라이브러리로서 컴파일되며 REAPER 안으로 가져오는 실제 확장 파일(reaper_reawwise.dll)을 생성합니다.

WwiseTransfer_Standalone (src/standalone)

이 포르젝트는 ReaWwise를 독립형 애플리케이션으로 시작하는 코드를 담고 있습니다. 주로 GUI 개발 및 시험에 사용됩니다. REAPER와는 연결되지 않습니다. REAPER에서 예상되는 데이터는 모형입니다.

WwiseTransfer_Shared (src/shared)

이 프로젝트는 애플리케이션의 모든 코어 컴포넌트와 GUI 요소를 담고 있습니다. 이 코드는 정적 라이브러리로 컴파일되며 확장 및 독립형 코드에 의해 의존성으로서 사용됩니다.

WwiseTransfer_Test (src/test)

이 프로젝트는 시험에 관한 모든 코드를 담고 있습니다.

의존성

서드 파티

  • Catch2: 프레임워크 테스트
  • JUCE: 애플리케이션 프레임워크
  • rapidjson: WAAPI 클라이언트의 의존성
  • reaper-sdk: REAPER API 헤더
  • trompeloeil: 모형 프레임워크

마지막 의존성은 AkAutobahn(WAAPI 클라이언트의 C++ 구현)과 Wwise SDK에서의 몇몇 헤더입니다. 이 의존성은 코드 베이스의 일부가 아니며 Audiokinetic 런처를 통해 따로 받을 수 있습니다.

다음 도표는 서로 다른 프로젝트와 의존성이 어떻게 연결되어 있는지를 보여줍니다.

reawwise_1

애플리케이션 아키텍처

이 섹션에서는 ReaWwise의 주요 구성 요소를 살펴보고 작동하는 방식을 살펴봅시다.

Preview Panel

Preview Panel을 구동하는 메인 구성 요소는 DawWatcher 오브젝트입니다. DawWatcher 는 주기적으로 DawContext 를 쿼리하여 Preview Panel의 콘텐츠를 업데이트해야 하는지의 여부를 알아냅니다. 또한 미리 보기에 영향을 줄 수 있는 무언가가 변경되었을 경우 Wwise에게 알림을 받습니다. Preview Panel이 업데이트되어야 하는 경우 DawWatcher DawContext 에서 렌더링되어야 하는 아이템과 Wwise에서 오브젝트 정보를 가져옵니다. 그런 다음 모든 내용을 함께 컴파일하여 Preview Panel로 전송될 미리 보기를 생성합니다.

DawContext 는 DAW를 표시하는 인터페이스입니다. DawWatcher와 같이 WwiseTransfer_Shared 안에 있는 코드가 파일 경로, 세션 정보, 세션 상태와 같은 정보를 REAPER에서 얻는 방식이죠. WwiseTransfer_Shared에 있는 코드는 REAPER에 대해 알지 못합니다. DawContext 를 구현하여 또 다른 DAW나 애플리케이션과 인터페이스하도록 할 수도 있습니다.

ReaWwise에서 DawContext 의 구체적인 구현은 ReaperContext입니다. 확장 API로의 모든 호출을 여기에서 볼 수 있습니다. 

아래는 미리 보기 패널 업데이트 과정을 보여주는 간소화된 연속적 도표입니다.

reawwise_2

Wwise로 전송하기

ReaWwise와 Wwise 간의 전송을 구동하는 주요 컴포넌트는 ImportTask 오브젝트입니다. 이 오브젝트는 WaapiClient 오브젝트를 사용하여 Wwise로의 여러 호출을 실행합니다. 또한 전송에 대한 모든 상세 정보를 추적하며, 이 정보는 전송이 끝날 때 상세 보고를 생성하는 데 사용됩니다. ImportTask 는 ReaWwise의 메시지 스레드를 차단하지 않도록 비동기적으로 실행됩니다.

WaapiClient 는 Wwise와 커뮤니케이션하는 데 사용되는 컴포넌트입니다. 이는 모든 WAAPI 요청과 응답 관리를 추상화하여 AkAutobahn 클라이언트에 대한 레이어 역할을 합니다. WaapiClientWatcher WaapiClient 와 함께 사용되는 컴포넌트이며 WAAPI로의 연결을 모니터링합니다. Wwise와의 여전히 연결되어 있는지 주기적으로 확인합니다.

다음은 가져오기 과정을 묘사하는 간소화된 연속적 도표입니다.

reawwise_3

애플리케이션 상태

ReaWwise는 JUCE ValueTree를 사용하여 컴포넌트간에 공유되어야 하는 데이터 및 상태 정보를 저장합니다. 이 데이터 구조체는 트리 모습을 하고 있으며 정수, 문자열, 불리언 등의 수많은 기본 데이터 유형을 저장할 수 있습니다. 커스텀 데이터 유형의 경우 특수 변환 템플릿을 사용할 수 있습니다. 컴포넌트는 자체를 리스너로 등록하면 ValueTree의 데이터의 변경 사항에 대한 알림을 받을 수 있습니다.

ReaWwise에서 GUI 컴포넌트는 ValueTree의 변경 사항을 주시할 수 있으며 이에 맞게 자신을 업데이트할 수 있습니다. 이는 컴포넌트를 서로 완전히 분리할 수 있게 해줍니다. 또한 비즈니스 논리와 표시 논리를 따로 유지할 수 있게 해줍니다. 다음 간소화된 연속적 도표는 ReaWwise의 텍스트 입력란이 해당 콘텐츠의 유효성에 따라 오류 상태를 보여주는 방식을 보여줍니다.

reawwise_4

시험

개발 단계 동안 저희는 여러 접근 방식으로 테스트를 해봤습니다. 여전히 프로젝트의 일부로 남아있는 첫 번째 접근 방식은 바로 단위 테스트입니다. 완전히 제거된 두 번째 방식은 종단간(end-to-end) 테스트입니다.

종단간(End-to-End) 테스트

종단간 테스트는 ADC21에서 조엘 노엘(Joel Noel)의 발표에서 영감을 받은 아이디어입니다. 조엘은 JUCE End to end라는 새로운 JUCE용 종단간 테스트 프레임워크를 발표했습니다. 이 도구는 어떤 JUCE 애플리케이션이든 javascript로 제어할 수 있게 해줍니다. 또한 어떤 JUCE 컴포넌트이든 쿼리할 수 있게 해줍니다. 예를 들어 애플리케이션에서 버튼이 클릭되도록 트리거한 후 확인 팝업이 표시되는지를 확인할 수 있죠.

결국 프레임워크는 잘 작동했지만 오토메이션된 방식으로 모든 컴포넌트(Reaper, ReaWwise, Wwise)가 함께 매끄럽게 작동하도록 하는 것이 거의 불가능했습니다.

글을 끝내며

2부로 제작된 이 블로그 시리즈에서는 애플리케이션 개발의 여러 다른 방면을 살펴보았습니다. 제품 개념화부터 사용자 경험 고려 사항 및 인터페이스 디자인까지 저희가 ReaWwise 제작에 적용한 기술 결정 및 소프트웨어 아키텍처 선택에 대해 자세히 살펴봤죠.

ReaWwise의 내부 작동 방식에 대해 더 자세히 알아보려면 GitHub에 제공된 audiokinetic/ReaWwise 코드를 확인하세요.

앤드류 코스타 (Andrew Costa)

소프트웨어 엔지니어, R&D

앤드류 코스타 (Andrew Costa)

소프트웨어 엔지니어, R&D

앤드류는 지난 8년 동안 콘텐츠 제작자를 위한 소프트웨어 개발자로서 일해왔습니다. 그는 소프트웨어와 음악 제작에 대한 큰 열정을 가지고 있습니다. 2021년부터 Audiokinetic의 개발자가 된 앤드류는 ReaWwise의 주요 개발자 중 한 명으로 작업해왔습니다.

댓글

댓글 달기

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

다른 글

새로운 기능 개요 2019.2

Profiler Filtering (프로파일러 필터링) Capture 세션을 보면, 주어진 시간 안에 생기는 많은 캡처 데이터를 어렵지 않게 발견할 수 있습니다. 이는...

14.2.2020 - 작성자: Audiokinetic

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

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

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

Wwise 2021.1 저작 플러그인 | 제 1부: 역사와 목표

Wwise 생태계에 대해 잘 알려지지 않은 특징 중 하나는 바로 확장성입니다. 프로젝트에 사용할 플러그인을 회사들이 직접 만들기도 하고 판매사는 (가끔은 저희 도움을 통해) 자체...

18.8.2021 - 작성자: 미셸 도네 (Michel Donais)

Impacter의 교차 합성 변형음 시각화하기

Impacter 플러그인 블로그 시리즈에 다시 오신 것을 환영합니다. 이전 두 블로그에서는 플러그인의 물리적 매개 변수와 이 매개 변수가 게임의 물리 시스템과 잘 통합될 수 있는...

2.2.2022 - 작성자: 라이언 돈 (RYAN DONE)

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

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

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

Wwise 2024.1 새로운 기능

Wwise 2024.1이 출시되었으며 Audiokinetic 런처를 통해 다운받으실 수 있습니다. 이 버전이 제공하는 새로운 기능을 간략하게 소개해드리려고...

8.11.2024 - 작성자: Audiokinetic (오디오키네틱)

다른 글

새로운 기능 개요 2019.2

Profiler Filtering (프로파일러 필터링) Capture 세션을 보면, 주어진 시간 안에 생기는 많은 캡처 데이터를 어렵지 않게 발견할 수 있습니다. 이는...

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

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

Wwise 2021.1 저작 플러그인 | 제 1부: 역사와 목표

Wwise 생태계에 대해 잘 알려지지 않은 특징 중 하나는 바로 확장성입니다. 프로젝트에 사용할 플러그인을 회사들이 직접 만들기도 하고 판매사는 (가끔은 저희 도움을 통해) 자체...