티스토리 뷰
최근 주변을 통해 App 에서 사운드 관련 작업의 논의를 했었다.
나는 예전에 사운드 디자인과 엔지니어링을 했었는데 Swift 로는 작업을 해본적이 없어 이번 기회에 조금 공부해보았다.
이전에 Max MSP 와 Sonic Pi 에서 작업해본적이 있긴 한데, 그때처럼 play(); 하면 되는게 아닌가? 하는 쉬운 생각이 들었다.
그래서 AVFoundation의 오디오 파트를 훑어봤는다. EQ와 input, output 채널 등을 사용할 수 있게 되어 있었으나 내가 필요한 오실레이터(OSC, Oscillator)는 Swift 에 기본제공되지 않는다.
오실레이터를 직접 구현해야 하고, 버퍼 등을 직접 만들어야 한다. 물론 이것도 재미있겠지만 오디오 작업에는 AudioKit 이라는 라이브러리를 많이 사용하는 것을 알게 되었다.
아무래도 Swift 로 오디오 작업을 하는것이 흔한 것은 아닌가보다. 자료가 많지는 않은데, AudioKit 의 Cookbook 앱이 잘되어있어서 참고하면서 어렵지 않게 작업해볼 수 있었다.
구현한 기능
- OSC로 파형, 노이즈 출력
- 10채널 EQ 연결
간단하게 위 형태의 앱을 만들어봤는데, OSC 로 파형을 출력하고 10채널 EQ를 적용할 수 있도록 구현했다.
오디오 작업을 할 때 시그널 체인(Signal Chain)은 매우 중요하다. pre와 post의 차이에 따라 의도하고자 하는 소리가 달라질 수 밖에 없고, input 과 output 을 제대로 연결하지 않으면 소리가 실종된다. 코드로 오디오를 다룰 때도 마찬가지이다. 시그널 체인에 맞게 input과 output 을 연결해주고, 최종 아웃풋을 시스템의 output 으로 연결하면 된다. AudioKit 에서는 이러한 시그널들을 Node 객체로 관리한다. 트리 자료구조의 Node 와 동일한 역할이다.
ProTools 나 Logic Pro 에서는 EQ, Compressor, Mixer 가 잘 되어있지만 코드에서는 직접 연결하거나 만들어줘야 한다. AudioKit 라이브러리는 AVFoundation 을 확장하여서 기본 구현되어있는 EQ와 Mixer는 물론, OSC 와 Compressor, Audio Player, Signal Visualization, 각종 이펙트 종류들(reverb, delay 등등)을 미리 구현되어 있다.
코드
앞서 얘기했듯이 AudioKit 의 시그널 체인은 Node 로 연결이 된다. input과 output에 사용되는 Mixer, Fader, Audio Source 등은 모두 Node 프로토콜을 채택하고 있다.
public class Mixer: Node, NamedNode {
...
}
public class ParametricEQ: Node {
...
}
public class Fader: Node {
...
}
그리고 아래와 같이 signal 을 객체 생성과 함께 연결해주었다.
private let inputMixer = Mixer()
private lazy var EQChainGroup: [ParametricEQ] = {
var eqArray = [ParametricEQ]()
eqParameters.enumerated().forEach { (index, parameter) in
if index == 0 {
eqArray.append(ParametricEQ(inputMixer))
} else {
eqArray.append(ParametricEQ(eqArray.last!))
}
}
return eqArray
}()
private var EQChainOutput: Node {
return EQChainGroup.last!
}
private lazy var masterFader: Fader = {
return Fader(EQChainOutput)
}()
public func start() {
let pinkNoise = PinkNoise()
pinkNoise.amplitude = 0.5
self.pinkNoise = pinkNoise
osc.frequency = AUValue(440)
osc.amplitude = oscParameter.gain
osc.setWaveform(Table(.sine))
inputMixer.addInput(pinkNoise)
inputMixer.addInput(osc)
pinkNoise.start()
osc.start()
engine.output = masterFader
try? engine.start()
}
시그널의 흐름을 그림으로 그려보면 이러한 형태가 된다. 나중에 오디오 파일같은 또 다른 오디오 소스가 생긴다면, Input Mixer 에 넣어주면 된다. 혹은 오디오 소스별로 EQ를 걸어줄수도 있겠다.
private func didSetEQParameter() {
eqParameters.enumerated().forEach { (index, parameter) in
EQChainGroup[index].centerFreq = Float(parameter.frequency)
EQChainGroup[index].q = parameter.q
EQChainGroup[index].gain = parameter.gain
}
}
private func didSetOSCParameter() {
osc.frequency = oscParameter.frequency
osc.amplitude = oscParameter.gain
switch oscParameter.type {
case .sine:
osc.setWaveform(Table(.sine))
case .sawtooth:
osc.setWaveform(Table(.sawtooth))
case .triangle:
osc.setWaveform(Table(.triangle))
case .square:
osc.setWaveform(Table(.square))
}
}
private func switchNoise() {
guard let pinkNoise else { return }
pinkNoise.isStarted ? pinkNoise.stop() : pinkNoise.start()
}
private func switchOSC() {
osc.isStarted ? osc.stop() : osc.start()
}
UI 에서 EQ와 Oscillator의 파라미터를 수정할 경우, EQ와 OSC에 접근하여 각 필드값을 수정하면 즉시 반영된다.
오랜만에 재미있는걸 해서 기분이 좋다 :) 컴프레서나 딜레이 같은거 직접 만들어보는것도 재밋겠다.
코드: https://github.com/jisu15-kim/AudioPlayground
GitHub - jisu15-kim/AudioPlayground
Contribute to jisu15-kim/AudioPlayground development by creating an account on GitHub.
github.com
'iOS' 카테고리의 다른 글
[iOS] String Catalog 로 Localization, 다국어 지원하기 (0) | 2025.04.19 |
---|---|
[iOS] SwiftUI 에서 TapGesture 가 동작하지 않을 때 (HighPriorityGesture) (1) | 2025.03.23 |
[iOS] Open API Generator 로 네트워크 코드 자동생성(2) - middleware로 토큰 관리, interceptor (0) | 2024.10.29 |
[iOS] demical keyboard type 에서 소수점이 comma로 나온다 (소수점 표기법) (0) | 2024.10.03 |
[iOS] Open API Generator 로 네트워크 코드 자동생성(1) (2) | 2024.09.04 |
- Total
- Today
- Yesterday
- audiokit
- Swift
- IOS
- open-api-generator
- AVFoundation
- self-hosted-runner
- swiftui 탭
- highprioritygesture
- demical
- string catalog
- flo
- 맥북에어 m4
- onTapGesture
- swift audio
- Xcode15
- Github action
- swiftui 제스처
- swift날짜
- DateFormatter
- ios 다국어
- 애플워치 데이터 전송
- easy cue
- SwiftUI
- audio kit
- watch connectivity
- keyboardtype
- openapi-generator
- avplayer
- ios웹소켓
- ios채팅
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |