티스토리 뷰

개발/Miscellaneous

YSE Sound Library

미누시 2019. 11. 29. 17:42

manual.pdf
0.18MB

이번 포스팅에서는 C++ 언어 기반의 YSE 사운드 라이브러리에 대해 알아보겠습니다. 일반적으로 C++에서 널리 알려진 라이브러리 중 하나는 fmod 라이브러리이며, YSE 라이브러리는 아마 들었을 때 생소한 라이브러리이라 생각합니다.

 

저 역시 최근에 우연한 기회를 통해서 YSE 라이브러리의 존재에 대해서 알게 되었습니다. 관련 자료를 찾던 중, 국내에 기초적인 레퍼런스마저 존재하지 않는 것으로 꽤나 애먹었었는데, 혹시 YSE 라이브러리에 대한 사용을 고민 중인 분들에게 도움이 되고자 포스팅하게되었습니다.

 

 

 

YSE 라이브러리란?


 

그림1. YSE

YSE 라이브러리는 C++ 기반의 오디오 라이브러리(audio library)입니다. YSE 홈페이지에서는 다음과 같이 설명하고 있습니다 :

YSE는 C++ 오디오 라이브러리입니다. Windows, Linux, MacOS, iOS 플랫폼에서 동작합니다. 우리의 목표는 YSE를 가능한 사용하기 쉽게 만드는 것입니다. 우리의 튜토리얼 및 데모 코드는 몇 시간만에 당신을 빠르게 적응시킬 것입니다.

단순함(Simplicity)은 한계에 대한 변명이 아닙니다. YSE는 대부분의 상업용 사운드 엔진보다 더 많은 기능(more features)을 지원하며, 우리는 더 많은 계획을 가지고 있습니다.

무엇보다도 YSE는 오픈소스입니다. Eclipse Public License를 통해 배포(release)되어 상업적인 목적을 가진 개발자가 오픈소스를 사용할 수 있습니다.

 

 

라이선스 이슈

그림2. YSE 제작에 사용되었던 다른 프레임워크 또는 라이브러리

YSE 라이브러리가 일부 구현에서 JUCE 프레임워크를 사용한 것으로 인해, JUCE 라이센스와 YSE 라이센스가 상충된다는 이슈가 있었습니다(링크). JUCE의 EULA 약관에서 GNU 라이센스여야 한다는 조항이 있었습니다.

JUCE Personal

JUCE Personal comes with one licence seat and aims to provide individuals with the opportunity to utilize JUCE free of charge. We provide this licensing option to grow the base of developers who can engage with JUCE and explore its capabilities. To this end, there is no Minimum Commitment. However, you may only use your JUCE Personal to release Applications up to a Revenue Limit of $50,000 (USD or currency conversion equivalent). This means that if gross revenue is generated or raised by you in the amount of $50,000 or more, which is gross revenue, without offsets of any kind and based on overall monies collected, then you may only continue to release your Application in connection with your JUCE Personal licence if (a) you license your Application as an open-source project under the GNU License, as further described in clause 1.8 below, or (b) you upgrade to JUCE Indie or JUCE Pro, as applicable. If you don’t want to release your Application under the GNU License, then you must upgrade to either JUCE Indie or JUCE Pro.

 

요약하자면, JUCE 이용자는 일정 금액 이상 창출시, JUCE 플랜을 유료로 업그레이드 하거나 또는 GNU 라이센스로 어플리케이션을 공개해야 한다는 의미인 것 같은데, YSE 라이브러리가 이클립스 라이센스로 채택했다는 점을 이슈로 삼는 것 같습니다.

 

이것에 대해서, 이곳, 그리고 이곳에서 라이브러리 제작자가 이용자와 논의한 이슈를 보실 수 있습니다.

 

현재 libYSE 2.0 버전을 통해 JUCE 지원을 제거함으로써, 라이센스 문제를 해결한 것으로 보입니다. 자세한 사항은 github 소스 페이지의 README 파일을 살펴보시기 바랍니다.

 

 

 

사용법


참고 : 본 사용법은 yse 라이브러리의 1.0 배포판(release)을 기준으로 작성되었습니다. 첨부파일에 yse 1.0 manual을 게재하였으니 참고하실 분들은 참고하시면 되겠습니다.

 

 

yse의 기본적인 사용법은 무척이나 간단합니다. 이번 섹션에서는 간단하게 음악을 출력하는 정도의 예제를 만들어 보겠습니다(공식 문서와의 레퍼런스를 읽을 때에도 참고할 수 있도록, 코드의 대부분을 데모 코드에서 참조하였음을 미리 밝힙니다).

주의 : yse의 dll 라이브러리를 프로젝트로 구성하는 방법은 별도로 설명하지 않습니다.

 

먼저, yse.hpp 파일을 인클루드(include)해야 합니다.

#include "yse.hpp"

 

yse 라이브러리의 시스템을 사용하기 위해서는 시스템을 초기화할 필요가 있습니다. yse에서는 다음의 코드로 수행할 수 있습니다 :

YSE::System().init();

 

여기서 YSE는 네임스페이스(namespace)이며, System은 functor(함수 객체)입니다. yse 라이브러리의 제작자에 따르면, YSE::System 클래스와 같은 시스템 클래스(system class)는 functor를 사용하며, 그 이유는 다음과 같다고 합니다 :

  • 베이스 객체(예를 들어, functor)가 항상 같기 때문에 코드 프래그먼트를 읽기 쉬워집니다.
  • 항상 생성되는 전역 객체와 달리, 함수 객체는 호출될 때만 생성됩니다.
  • 객체가 생성되었는지 여부를 추적할 필요가 없어집니다. 단지 필요할 때마다 사용하면 됩니다. 이미 내부적으로 생성되었을 수도 있고, 그렇지 않으면 재사용하기 위해 생성할 것입니다. 둘 모두 같은 일을 수행합니다.
  • 왜냐하면, functor가 객체의 참조를 반환하기 때문에, 중괄호(brace) 없이 실제 객체처럼 사용될 수 있습니다.

 

다른 functor 객체들의 목록은 다음과 같습니다:

YSE::System();
YSE::Listener();
YSE::Reverb();
YSE::Log();
YSE::IO();

// common sound channels
YSE::ChannelMaster();
YSE::ChannelGui();
YSE::ChannelFX();
YSE::ChannelMusic();
YSE::ChannelAmbient();
YSE::ChannelVoice();

 

시스템이 초기화되었으므로, 다음으로는 소리를 출력해보도록 하겠습니다. 공식 문서의 예제에서 ogg 파일로 수행하므로, 여기서도 ogg 파일로 예제를 작성하겠습니다(ogg, wav 파일에 대해서만 기능하는 것 같습니다).

먼저, 소리를 재생하기 위한 객체를 생성합니다.

YSE::sound ExampleSound;

 

여기서 YSE::sound는 typedef로 선언된 것으로써 원형은 YSE::SOUND::interfaceObject입니다. YSE에서는 사용자의 편의성을 위해 복잡한 namespace 계층을 가지는 클래스들을 typedef로 재정의한 형태를 많이 볼 수 있습니다.

이후, 다음의 코드로 사운드를 생성합니다.

ExampleSound.create("Example.ogg");

 

다음의 함수들로 사운드의 상태를 점검할 수 있습니다(예외 처리 등에 쓸 때) :

/* 사운드가 유효한지 확인합니다 */
ExampleSound.IsValid();

/* 사운드가 재생중인지 확인합니다 */
ExampleSound.IsPlaying();

 

사운드를 재생할 때는 다음의 함수를 사용할 수 있습니다 :

ExampleSound.Play();

 

여기서 한 가지 더 말씀드리자면, YSE 함수들 중에서 setter 기능을 수행하는 함수들은 객체의 참조자를 다시 반환하는데, 이를 이용해서 메소드 체이닝(method chaining)을 수행할 수 있습니다. 다음은 그 예입니다 :

ExampleSound.setRelative(true).setDoppler(false).setPosition(YSE::Vec(1,1,1)).play();

 

위 코드만으로는 사운드가 실행되지 않습니다. yse 사운드 시스템은 주기적으로 업데이트를 해줘야하기 때문입니다. 따라서 지속적으로 수행되는 루프 안에 다음의 코드를 삽입해야 합니다 :

while(true)
{
    YSE::System().update();
}

 

단순히 update 함수가 계속 실행되어야 한다는 의미에서 코드를 작성한 것이니, 무한 루프로 인해서 cpu 점유율이 올라간다던가, 유휴 상태로 만들어야 한다던지 가변 프레임을 사용해야 한다던지의 세부적인 논의는 생략하겠습니다. 어쨌든, 여기까지 작성된 코드면 사운드가 제대로 메모리에 적재되었을 때 실행은 됩니다.

이후, 프로그램을 종료할 때, yse 시스템 역시 정리할 필요가 있습니다. 이 때 호출되어야 하는 코드는 다음과 같습니다 :

YSE::System().close();

 

이 코드들을 깔끔하게 정리하면 다음과 같이 작성할 수 있습니다 :

#include <iostream>
#include <thread>
#include "yse.hpp"
#include "wincompat.h"


using namespace std;

int main()
{
    YSE::System().init();

    YSE::sound ExampleSound;
    ExampleSound.create("Example.ogg");
    if(ExampleSound.isValid() == false)
    {
        cout << "ExampleSound가 유효하지 않습니다.\n";
        return 0;
    }

    bool bLooping = true;
    while(bLooping)
    {
        if (_kbhit()) 
        {
            char ch = _getch();
            switch (ch) 
            {
              case ' ': sound.toggle(); break;
              case 'a': sound.play(); break;
              case 's': sound.pause(); break;
              case 'd': sound.stop(); break;
              case 'e': bLooping = false; break;
            }
          }

        ExampleSound.update();

        /* 20ms를 유휴 상태로 전환합니다. */
        this_thread::sleep_for(chrono::milliseconds(20);
    }

    YSE::System().close();
    return 0;
}

 

 

 

레퍼런스


참고 자료
YSE 홈페이지
YSE - RERENCE MANUAL
Github - yse-soundengine
JUCE 5 EULA

댓글