본문 바로가기
Coding/Flutter + Dart

Flutter 프로젝트에서 Faust DSP 사용하기

by potatosalad 2023. 4. 9.

얼마 전 eqTrainer 갈아엎기 - 1편을 작성한 이후로 Faust DSP를 플러터 프로젝트에 결합하는 과정을 시도해왔습니다.

 

몇 일 간 이리저리 시도한 끝에 해당 작업을 성공하기는 했는데, 기기에서 재생되는 오디오 출력을 Faust DSP에 연결하는 방법은 끝끝내 찾지 못하였습니다. 실시간으로 오디오 필터를 입히는 기능이 반드시 필요한 만큼, 결국 다른 방법을 찾거나 조금 더 깊게 파고 들어가봐야한다라는 결론에 도달했습니다.

 

비록 Faust는 제가 원하는 기능을 단번에 제공하지 못했지만, Sawtooth를 비롯한 다양한 음성 신호를 Faust 자체적으로 생성하고, 이를 필터링하는 기능은 문제없이 작동하는 것을 확인했기에, MIDI 신호 처리나 음파 생성 기능을 요구하는 앱을 개발하고자 하시는 분들에게는 충분히 공유할 가치가 있는 내용이라고 판단하여 글을 작성하게 되었습니다.

 

아래 내용들은 윈도우 환경에서, Android Studio를 사용하는 것을 전제로 진행됩니다.

 

FAUST (Functional AUdio STream)?

 

Faust (Functional Audio Stream) is a functional programming language for sound synthesis and audio processing with a strong focus on the design of synthesizers, musical instruments, audio effects, etc. created at the GRAME-CNCM Research Department. Faust targets high-performance signal processing applications and audio plug-ins for a variety of platforms and standards.

The core component of Faust is its compiler. It allows to "translate" any Faust digital signal processing (DSP) specification to a wide range of non-domain specific languages such as C++, C, LLVM bit code, WebAssembly, Rust, etc. In this regard, Faust can be seen as an alternative to C++ but is much simpler and intuitive to learn.

Thanks to a wrapping system called "architectures," codes generated by Faust can be easily compiled into a wide variety of objects ranging from audio plug-ins to standalone applications or smartphone and web apps, etc.

- https://faust.grame.fr/

 

위와 같은 특성을 가진 Faust를 플러터 프로젝트에서 활용하기 위해, Faust2Api를 사용하고자 합니다.

 

다양한 언어로 컴파일이 가능한 Faust를 플러터 프로젝트에 도입하는 방법은 여러가지가 있을 수 있겠지만, Faust2Api는 플랫폼과 무관하게 동일한 API를 제공한다는 점에서 크로스플랫폼 프레임워크인 Flutter에서 사용하기에 가장 적합한 방법이라고 느꼈습니다.

 

Windows Subsystem for Linux 설치

 

앞서 설명한 Faust2api는 Faust 언어로 작성된 .dsp 파일을 기기 환경에 맞게 컴파일해주는 역할을 합니다.

아쉽게도 해당 스크립트는 bash에서만 동작하기 때문에, 저처럼 윈도우 환경을 사용 중인 경우 bash를 활용하기 위해 WSL 설치가 필수적입니다.

 

WSL 설치를 안내하는 글은 이미 많이 올라와 있기도 하고, 분량 조절을 위해 생략하도록 하겠습니다.

 

Android Studio 환경 준비하기

 

 

SDK Manager를 실행하여 SDK Tools 아래에 포함된 CMake, NDK를 설치합니다.

 

이후에는 특별히 설정할 것이 없습니다. 제가 준비한 Template을 Github에서 Clone해 와서 사용하시면 됩니다.

https://github.com/potatosalad775/flutter_faust_example

 

GitHub - potatosalad775/flutter_faust_example: Template for Flutter & Faust DSP Project

Template for Flutter & Faust DSP Project. Contribute to potatosalad775/flutter_faust_example development by creating an account on GitHub.

github.com

 

Faust 코드 작성하기

 

 

메인 디렉터리에 DSP 폴더를 만들었습니다. 이 폴더 내부에 Faust 언어로 작성된 .dsp 파일을 담고자합니다.

어차피 .dsp 파일은 컴파일되어 프로젝트에서 직접적으로 사용되지는 않으므로, 원한다면 아무 경로에나 생성해도 되긴 합니다.

 

import("stdfaust.lib");
gate = button("gate") : si.smoo;
gain = hslider("gain",1,0,1,0.01);
process = os.sawtooth(440) * gate * gain <: _,_;

 

위 코드는 440hz의 Sawtooth 신호를 생성하고, 게이트 노드와 게인 노드를 뒤에 연결한 뒤 스테레오 채널로 분배하는 간단한 코드입니다.

 

Faust 언어 사용 방법은 아래 링크를 참고하여 학습할 수 있습니다. 

온라인 IDE를 통해 Faust 코드를 실시간으로 실행해볼 수도 있습니다.

 

Faust 코드 컴파일하기 - Faust2api

WSL을 설치했다면, Powershell을 실행하여 'bash'를 입력하는 것만으로 간단하게 bash 사용이 가능합니다.

 

sudo apt-get update
sudo apt-get install faust

 

이후 위 코드를 입력하여 Faust 패키지를 설치합니다.

 

cd /mnt/DIR_TO_PROJECT

 

그 다음, cd 명령어를 통해 프로젝트 경로로 이동합니다.

WSL에서는 /mnt/ 다음에 주소를 이어 적는 방식으로 윈도우 내 파일에 접근이 가능합니다.

 

Android / iOS 플랫폼에 따라 서로 다른 옵션을 부여해서 faust2api 명령어를 사용해야 합니다.

 

컴파일된 Faust 코드 적용하기 - 1. 안드로이드

 

faust2api -android ./DSP/main.dsp

 

위 명령어를 bash에 입력하여 .dsp 파일을 컴파일합니다.

컴파일이 완료되면 faust_dsp.zip 파일이 생성됩니다. 해당 압축파일의 내용물을 적절한 위치에 집어넣어야 합니다.

 

 

해당 압축파일 안에는 cpp 폴더, java 폴더, README.md 파일이 생성되어 있습니다. (사진에서 보이는 main.dsp는 없어요)

README.md 마크다운 파일에는 Faust2api에서 제공하는 Android API에 관련된 내용이 설명되어 있으니 읽어볼만 합니다.

 

 

faust2api로 컴파일된 파일들을 적용하기 위해 아래 과정을 거쳐 파일들을 적합한 디렉터리에 옮겨넣어야 합니다.

cpp 폴더 속 내용물은 \프로젝트\android\app\src\main\ 경로에 넣어주고,

java 폴더 속 내용물은 \프로젝트\android\app\src\main\java\com\DspFaust 경로에 넣어줍니다.

 

컴파일된 Faust 코드 적용하기 - 2. iOS

 

faust2api -ios -nozip -target ./ios/Runner/DSP ./DSP/main.dsp

 

위 명령어를 입력하여 dsp 파일을 컴파일합니다.

 

iOS는 특별히 압축을 해제할 필요도, 컴파일된 파일을 옮겨줄 필요도 없습니다.

 

테스트하기

 

 

이제 Android Emulator에서 실행해봅시다.

Beep 버튼을 눌렀을 때 Sawtooth 톤이 생성되고, Gain 슬라이더를 통한 음량 조절도 잘 작동하는 것을 확인할 수 있었습니다.

 

아쉽게도 .dsp 파일을 수정할 때마다 faust2api를 통한 컴파일 과정을 다시 한 번 거쳐야하고, 그렇게 컴파일되어 추가된 파일은 Flutter의 특징 중 하나인 Hot Reload / Restart의 영향을 받지 않기 때문에 main.dart 실행을 중단하고, 다시 시작하는 과정을 거쳐서 Gradle이 수정된 C++ 파일을 다룰 수 있도록 해주어야 합니다. 

댓글