확장팩 FFF 모음 정리 링크


매우매우매우 기술적인 얘기만 한가득 들어있음

중간에 사진 여러장 나오는건 저번 fff부터 얘네 사진 삽입 구조를 바꿨는데 디시에서는 그걸 구현할수가 없고

그냥 나열하자니 사진 20장으로 스압만 만들어질거같아서

움짤로 편집해서 넣었음

움짤 프레임간 인터벌이 너무 짧거나 길다면 피드백좀 주셈


그리고 기술적 어쩌고 나오는 부분은 솔직히 잘 이해하기 힘들어서 오역 있을 수 있음



https://www.factorio.com/blog/post/fff-407



FFF #407 - 사운드트랙 자동화

게시자 Albert, Donion

2024-04-19



안녕하세요,

오늘도 음악 여행을 계속하겠습니다.



동기부여 - Albert


지난 주(FFF-406)에는 팩토리오 우주 시대 확장팩의 음악에 대한 일반적인 접근 방식을 소개했습니다. 또한 5시간 분량의 음악을 커버할 뿐만 아니라 이를 뛰어넘는 새로운 기법도 있다고 언급했습니다.


이 자동 음악 제작 방식은 팩토리오를 사용하기 전인 오래전부터 실험해왔던 방식입니다.

저는 액션 스크립트로 프로그래밍된(네, 꽤 오래되었죠) 임의의 베이스 섹션 위에 임의의 멜로디와 임의의 리듬 베이스로 많은 연주를 해봤어요. 그 결과는 꽤 강렬했지만 완성된 트랙이라고 할 만큼 좋지는 않았죠.


팩토리오 우주 시대 확장팩의 5시간 사운드트랙 프로젝트가 시작되었을 때, 저는 바로 그 옛날 실험을 떠올렸습니다. 하지만 Petr가 작곡을 하고 Donion이 프로그래밍을 하니 상황이 달라 보였어요. 저는 과감히 이 길을 택했습니다. 이제 저는 이것이 좋은 결정이었다고 확신합니다.




가변 음악 트랙 - Donion


이러한 트랙은 선택할 때마다 다르게 재생되며, 일종의 절차적으로 생성된 음악입니다. 하지만 무작위 재생에 너무 열중하고 싶지는 않습니다. 가변 트랙은 단일 트랙의 변형 세트에 가깝습니다(모두 녹음할 필요 없이). 이러한 트랙은 메인 트랙 사이에 재생되는 간주 음악을 대신합니다(숨겨진 설정에서 디버그하지 않는 한). 목표는 게임에서 수십 또는 수백 시간을 보낸 후에도 여전히 일반 음악이 사운드트랙의 대부분을 차지하고 음악에 약간의 다양성을 제공하는 것이 목적입니다.


가변 음악 트랙은 프로토타입에서 정의되며 모더가 완전히 이용할 수 있습니다. 다음은 가변 트랙을 정의하는 데 사용되는 컴포넌트입니다:



샘플


가장 작은 구성 요소입니다. 다른 규칙에 따라 재생되는 개별 음악 조각입니다. 샘플은 서로 이어서 재생되므로 한 샘플이 끝나면 다음 샘플로 원활하게 재생이 이어집니다.



레이어


샘플은 레이어로 그룹화됩니다. 레이어는 개별 샘플이 함께 구성되는 방식을 결정합니다. 샘플을 무작위로 선택하거나 사용 가능한 모든 샘플을 섞어 각각 정확히 한 번만 재생하는 것처럼 간단할 수도 있고, 현재 다른 레이어에서 재생 중인 샘플을 기준으로 샘플을 선택하는 등 더 복잡할 수도 있습니다. 레이어에는 특정 방식으로 샘플이 겹치는 하위 레이어도 포함될 수 있습니다. 지연된 시작, 셔플 레이어의 반복 횟수 및 반복 사이의 일시 정지, 겹치는 하위 레이어의 오프셋 등을 정의하는 여러 속성을 사용하여 레이어 내에서 추가 변형을 수행할 수 있습니다. 이러한 속성은 레이어 자체에서 또는 트랙의 현재 상태에 따라 제공됩니다.


레이어와 해당 샘플은 각 트랙이 자체적으로 정의한 최소 시간 단위로 정렬되어 재생되므로 일종의 시간 격자가 만들어집니다.


레이어를 구성하는 방식이 변화의 주요 원인입니다.



섹션


섹션은 레이어의 모음입니다. 트랙에는 섹션이 하나 또는 여러 개 있을 수 있습니다. 어떤 섹션이 사용되는지는 트랙 상태에 따라 결정됩니다. 또한 섹션은 겹칠 수 있습니다. 마지막으로 섹션에는 일반 음악으로 재생되는 간주곡이 포함될 수 있어 일부는 가변, 다른 일부는 정적인 하이브리드 트랙을 구성할 수 있는 옵션이 제공됩니다.



상태


상태와 상태 간 전환은 가변 트랙의 구성 방식을 정의하는 가장 높은 단계의 방법입니다. 어떤 섹션을 재생할지, 이전 섹션과 겹칠지 여부를 선택하고 현재 섹션의 레이어에 적용되는 여러 레이어 속성을 정의합니다.


상태 간 전환은 경과 시간을 기준으로 하거나 특정 레이어 종료에 연결할 수 있습니다. 여러 개의 가능한 다음 상태를 서로 다른 가중치로 정의할 수 있으므로 일부 전환은 다른 상태보다 확률이 높습니다. 다음 상태 후보에는 추가 조건을 정의할 수 있으며, 이러한 조건이 충족되어야 전환을 고려할 수 있습니다. 예를 들어 다음 상태 선택 시 특정 샘플이 특정 레이어에서 재생 중인 경우에만 전환이 발생하도록 설정할 수 있습니다.





이제 가변 트랙이 무엇으로 구성되는지 알아봤으니 트랙이 어떻게 구성되는지 몇 가지 예를 살펴보겠습니다.


이 예시는 아직 진행 중인 기술 시연용 데모임을 양해해 주시기 바랍니다. 일부 세부 사항은 변경될 수 있습니다. 여기 나온 음악 자체는 출시될 게임의 사운드트랙을 대표하지 않으며, 이 샘플은 상당히 오래되었고 단순히 설명 목적으로 제작되었습니다!


첫 번째 예는 세 개의 섹션으로 구성된 트랙입니다. 각 섹션에는 두 개의 하위 레이어로 구성된 베이스 레이어, 두 개의 하위 레이어로 구성된 중간 레이어, 멜로디 레이어 및 간주 등 총 세 개의 레이어가 있습니다. 상태 간 전환은 멜로디 레이어를 마무리로 합니다.





이 트랙의 인스턴스는 이렇게 들릴 수 있습니다:

https://cdn.factorio.com/assets/blog-sync/fff-407-example1_1.mp3


개발중인 버전을 사용하여 게임 내에서 녹화했습니다.


이미지는 예시일 뿐이며 실제 녹화된 음악과는 일치하지 않습니다. 다음은 실제 타임라인입니다:


0:01: 트랙이 시작 상태에서 시작되며, 섹션 2가 무작위로 선택됩니다.

0:01: 베이스 레이어가 시작됩니다.

0:12: 중간 레이어가 시작됩니다.

0:17: 멜로디 레이어가 시작됩니다.

0:44: 멜로디 레이어가 첫 번째 반복을 완료하고 두 번째 반복 전에 일시정지를 대기합니다.

0:51: 멜로디 레이어가 두 번째 반복을 시작합니다.

1:19: 멜로디 레이어가 두 번째이자 마지막 반복을 완료하고 재생을 완료하기 전에 일시정지를 대기합니다.

1:23: 멜로디 레이어 재생이 끝나면 인터 상태로 전환되고 이전 상태와 다른 섹션이 무작위로 선택되며, 이 경우 섹션 0이 선택됩니다.

1:23: 베이스 레이어와 중간 레이어가 계속 재생되며, 이제 섹션 0의 샘플을 사용합니다.

1:23: 멜로디 레이어가 다시 재생되기 시작합니다.

1:42: 멜로디 레이어가 첫 번째이자 유일한 반복 재생을 완료합니다. 이번에는 일시 중지 없이 바로 계속 상태로 전환됩니다.

1:42: 상태 시작에서 선택한 섹션이 다시 사용됩니다.

1:42: 멜로디 레이어는 시작 상태와 동일한 샘플 셔플링을 사용합니다.

2:09: 멜로디 레이어가 첫 번째이자 유일한 반복 재생을 완료합니다. 이후에도 멈추지 않고 즉시 완료 상태로 전환합니다.

2:09: 섹션 1이 아직 사용되지 않은 유일한 섹션으로 선택되었습니다.

2:35: 멜로디 레이어의 첫 번째 반복이 끝나면 멈춤 없이 두 번째 반복이 이어집니다.

3:03: 멜로디 레이어가 두 번째이자 마지막 반복을 완료합니다.



이 두 번째 예는 섹션이 하나만 있는 트랙을 보여 주지만 고정된 시간 간격으로 상태 간에 전환할 때 겹쳐집니다. 섹션에는 세 개의 레이어가 있습니다. 첫 번째 레이어에서 특정 샘플이 재생되는 경우 간주곡을 재생할 수도 있습니다.






이런 식으로 들릴 겁니다:

https://cdn.factorio.com/assets/blog-sync/fff-407-example2_1.mp3


개발중인 버전을 사용하여 게임 내에서 녹화했습니다.







기술적 과제 - Donion


사운드트랙에서는 트랙의 전환 타이밍을 정확하게 맞추는 것이 중요하다는 것이 밝혀졌습니다. 저도 충격을 받았어요.



샘플 대기열


트랙의 전체 템포를 유지하고 오디오 아티팩트(소음)를 방지하려면 샘플을 간격 없이 차례로 재생해야 하는데, 최근 포럼의 누군가가 이를 어렵게 알아냈습니다. 음악 플레이어는 다른 게임 로직과 마찬가지로 초당 60회 업데이트됩니다. 현재 샘플의 재생이 완료되었는지 확인하여 다음 샘플 재생을 시작하는 것만으로는 충분하지 않습니다. 샘플 사이에 최대 16.67ms(1/60초)의 간격이 있어 템포가 손상될 수 있기 때문입니다.일반 업데이트 로직 외부에서 별도의 스레드로 검사를 수행하거나 샘플 재생이 완료된 시점에 대한 콜백을 사용하면 사용 중인 SDL_Mixer 라이브러리 (버전 2.0.4)에서 오디오 데이터가 혼합되는 방식 때문에 작동하지 않을 수 있습니다.


현재 설정에서 오디오는 512개의 샘플(음악 샘플이 아닌 오디오 신호 샘플)로 믹싱되며, 샘플링 주파수가 44.1kHz인 경우 믹싱 간격은 약 11.6ms입니다. 샘플 재생이 끝나는 정확한 순간을 감지하더라도 그 순간 바로 다음 샘플 재생을 시작할 수는 없습니다. 다시 최대 11.6ms의 간격이 발생하기 때문입니다. 우리에게 정말 필요한 것은 음악 샘플을 대기열에 넣는 방법입니다.


SDL_Mixer 라이브러리는 이러한 기능을 제공하지 않기 때문에 SDL_Mixer 자체에 약간의 수정을 가하여 SDL_Mixer 위에 직접 구축해야 했습니다. 오디오 백엔드에 기능을 추가해야 했던 것은 이번이 처음이 아니었기 때문에 걱정하지 않았고 대기열 시스템이 상당히 빠르게 작동했습니다. 이제 음악 플레이어는 여유로운 16.67ms 창에서 샘플을 대기열에 넣고 별도의 스레드가 샘플을 정확하게 연결하는 작업을 처리하는 동안 SDL_Mixer는 그런 일이 있었는지조차 모를 수 있게 됩니다.




샘플 간 전환


위 그림에서 볼 수 있듯이 동일한 샘플을 다른 길이로 재생할 수 있습니다. 예를 들어 그림 5의 첫 번째 예에서 샘플 3(노란색)은 먼저 그리드의 세 단위로 재생된 다음 네 단위로 재생됩니다. 동일한 샘플의 변형을 여러 길이로 저장하지 않는 한(실제로는 그렇지 않습니다), 다음 샘플을 재생하기 전에 샘플을 짧게 잘라야 하는 경우가 많습니다. 이렇게 하면 불쾌한 오디오 소음이나 치찰음이 발생할 수 있습니다. 음악 또는 동영상 플레이어에서 재생 위치를 변경할 때도 비슷한 일이 발생할 수 있습니다. 오디오 신호의 레벨이 급격히 상승하면서 '티딕' 또는 '쾅'하는 소리가 나는 것입니다. 큰 간격을 사용하려는 경우 신호가 불연속적이 됩니다.


이전 버전으로 촬영한 이 녹음에서 클리핑 소음이 들릴 수 있습니다(볼륨을 높여야 들릴 수도 있습니다). 이에 대해 뭔가 조치를 취해야 한다는 것은 분명합니다.

https://cdn.factorio.com/assets/blog-sync/fff-407-example1.mp3


이 문제를 해결하는 방법은 샘플을 짧은 시간 동안, 예를 들어 10ms씩 차례로 페이드아웃 및 페이드인하는 것입니다. 이렇게 하면 전환이 부드럽고 매끄럽게(연속적으로) 이루어집니다. 일부 오디오 처리 애플리케이션은 기본적으로 이런 종류의 작업을 자동으로 수행할 수 있습니다. 간단하게 들리고 SDL_Mixer는 샘플을 페이드 인 및 페이드 아웃하는 방법을 제공하는데, 무엇이 문제일까요? SDL_Mixer에 내장된 페이드 기능은 11.6ms 간격으로 믹싱되는 전체 청크에 대해 동일한 목표 볼륨을 계산합니다. 즉, 전체 페이드가 하나의 믹싱 간격에 맞고 볼륨 레벨이 하나만 남게 되므로 페이드 아웃이 전혀 발생하지 않습니다. 페이드 아웃 시간을 정확하게 맞추는 것이 불가능하다는 것은 말할 것도 없고요.


다행히 SDL_Mixer는 샘플에 필터(효과)를 붙이는 기능을 지원합니다. 필터에서는 오디오 데이터로 원하는 모든 것을 할 수 있습니다. 샘플 레벨 정밀도(다시 말하지만 오디오 신호 샘플)로 자체 페이더를 필터로 작성하는 것은 간단합니다. 페이드가 필요한 순간까지 지연되는 옵션을 추가하면 짜잔, 더 이상 번거로운 클릭이 필요하지 않습니다.




레이어 정렬


모든 레이어와 서브 레이어가 함께 재생될 때 타이밍도 중요합니다. 주어진 트랙의 최소 시간 단위로 정의된 시간 그리드에 맞춰 정렬(동기화)해야 합니다. 첫 번째 예제에서는 ~286ms(12,600샘플) 시간 단위를 사용했습니다.


SDL의 오디오 스레드가 믹싱 중일 때는 다른 스레드(게임의 나머지 부분)와의 경쟁 조건을 피하기 위해 오디오 장치를 잠가야 합니다. 주어진 시간에 하나의 스레드만 활성 오디오 리소스를 변경해야 합니다. 같은 이유로 샘플 재생을 시작하려는 경우 오디오 장치가 잠깁니다.


가변 트랙의 일부 레이어가 트랙 자체가 시작된 후 한동안 재생이 시작되지 않더라도 정확한 시간에 레이어를 시작할 방법이 없고, 'x밀리초 후에 재생 시작' 기능이 없으며, 설사 있다 하더라도 앞서 언급한 덩어리가 섞이는 문제가 발생하므로 모든 레이어를 동시에 시작해야 정렬이 되고, 비활성화된 레이어는 무음으로 재생됩니다.


오디오 스레드는 언제든지 오디오 장치에 뛰어들어 잠글 수 있습니다. 예를 들어 총 5개의 레이어 중 처음 2개의 레이어를 시작하는 순간 불운이 발생하면 나머지 3개의 레이어는 약 11.6ms 후에 시작되어 정렬이 맞지 않게 됩니다. SDL_Mixer는 명시적인 잠금 기능을 제공하지 않습니다. SDL 자체에서 이러한 기능을 제공하지만 SDL_Mixer는 대부분의 작업에 대해 잠금을 획득하려고 시도하므로 약간의 조정이 필요하지만 추가하기 어려운 것은 아닙니다.


레이어가 트랙 중간에 아무것도 재생되지 않을 때도 비슷한 문제를 해결해야 합니다. 필요한 순간에 다시 시작할 수 없기 때문에 그냥 멈출 수 없습니다. 시간 그리드에 맞춰 무음으로 재생됩니다.







지난 주 자주 묻는 질문 - Donion


- 원격으로 다른 표면을 볼 때와 표면을 전환할 때 어떤 음악이 재생되나요?


각 트랙은 하나의 행성 또는 우주 플랫폼에 연결되어 있습니다. 현재 보고 있는 표면(캐릭터를 제어할 때 일반 모드 또는 원격 뷰어)을 읽어들여서 적절한 음악 트랙을 선택합니다. 표면 사이를 전환할 때 다시 캐릭터로 또는 원격 뷰어로 전환하면 음악 트랙이 전환됩니다. 각 표면의 현재 트랙 진행 상황이 기억되므로 음악이 중단된 표면으로 다시 전환하면 새 트랙을 다시 시작하는 대신 기억된 위치에서 트랙이 재개됩니다. 이렇게 하면 계속 멈췄다가 다시 시작할 필요 없이 음악을 포함한 표면 전환의 즉각적인 피드백을 받을 수 있습니다.


현재는 서로 다른 표면의 트랙 간 전환이 즉각적으로 이루어집니다. 그러나 테스트와 피드백에 따라 변경될 수 있으며, 짧은 페이드인/페이드아웃과 같은 전환이 추가될 수도 있습니다.




- 음악이 더 역동적이고 게임 진행에 반응하도록 만들 수 있을까요?


지난 주에는 기술적인 세부 사항을 다루지 않기 위해 음악 플레이어가 게임 상태에 대해 아무것도 모른다는 점에 대해 정확히 설명하지 않았습니다. 플레이어가 어떤 표면을 보고 있는지에 대해서는 알고 있습니다. 하지만 음악 플레이어가 고려하는 게임 상태의 유일한 변수는 이것뿐입니다.


엔진에 이러한 한계가 있다고 해서 더 많은 정보를 음악 플레이어에 전달하는 것이 불가능한 것은 아닙니다. 하지만 음악 자체는 수년 전부터 이러한 시스템을 염두에 두고 작곡해야 합니다. Petr가 이 모든 것이 함께 작동하는 방식으로 작곡할 수 있도록 모든 조건을 미리 잘 정의해야 합니다. 어려운 부분입니다. 불가능하다는 말은 아니지만 저희는 다른 길을 택했습니다.


간단히 말해서, 지금까지 더 역동적인 음악이 나오지 않았다면 앞으로도 나오지 않을 가능성이 높습니다.




- 음악을 세밀하게 제어할 수 있나요?


사용자 지정 재생 목록이나 표면별 설정과 같은 복잡한 컨트롤을 직접적으로 게임에 추가할 계획은 없습니다. 해당 기능을 정말 원하는 사람이 있다면 간단한 모드를 만들어 해당 기능을 구현할 수 있습니다.


2.0에서는 키를 바인딩하여 현재 재생 중인 트랙을 건너뛰고, 이전에 재생한 트랙으로 돌아가거나 음악을 일시 중지/재개할 수 있는 옵션이 추가되었습니다.




- 음악이 항상 재생되나요?


아니요, 현재 1.1 버전과 마찬가지로 트랙 사이에 무작위로 일시정지가 발생합니다. 우주 시대 확장팩의 트랙의 길이에 더 잘 맞도록 일시정지 시간을 조정할 것이며, 이는 테스트 피드백에 따라 달라질 수 있습니다.




- 우주 시대 확장팩의 사운드트랙은 별도로 판매되나요?


예, 기본 게임의 사운드트랙과 동일한 디지털 버전의 사운드트랙을 구매할 수 있습니다.





항상 그렇듯이, 평소와 같은 장소에서 생각의 변형을 인스턴스화하세요.