모든 글

SignalMetric 만들기: 하나의 라이브 신호를 보는 네 가지 방식

실시간 미터, 스펙트럼, Timeline, 파형을 하나의 신호로 일관되게 유지하고 UI backlog를 피하는 SignalMetric의 설계를 다룹니다.

iOS오디오 엔지니어링AVAudioEngineDSP아키텍처
SignalMetric 만들기: 하나의 라이브 신호를 보는 네 가지 방식

오디오 분석기에서 어려운 일은 움직이는 선을 그리는 것이 아닙니다. 모든 선이 같은 시점의 같은 신호를 가리키게 하면서, 오디오 콜백을 UI 스케줄러로 만들지 않고 화면이 잠시 느려져도 백로그가 계속 늘지 않게 하는 일입니다.

SignalMetric은 한 가지 결정을 중심에 두었습니다. Monitor, Spectrum, Timeline, Scope는 서로 쫓아가는 독립 도구 네 개가 아니라 하나의 분석 프레임을 읽는 네 가지 방식이어야 합니다.

Flow diagram Preparing diagram
View diagram source
flowchart LR
    A[라이브 마이크 입력] --> D[오디오 캡처]
    B[가져온 파일 또는 로컬 녹음] --> C[AVAudioPlayerNode]
    C --> E[메인 믹서 Tap]
    D --> F[2,048 샘플 캡처 창]
    E --> F
    F --> G[직렬 ScopeAnalyzer]
    G --> H[최신 ScopeFrame]
    H --> I[ViewModel이 30 FPS로 게시]
    I --> J[Monitor]
    I --> K[Spectrum]
    I --> L[Timeline]
    I --> M[Scope]
    D --> N[상한이 있는 녹음 기록기]

그림 자체는 익숙합니다. 계기가 신뢰를 얻는지는 경계를 어떻게 다루는가에 달려 있습니다.

소스가 바뀌어도 분석 계약은 하나

SignalMetric에는 권한 없는 Demo, Live Mic, 가져온 오디오, 명시적 로컬 녹음의 네 소스 상태가 있습니다. 이들은 AVAudioEngine에 같은 지점으로 들어가지 않습니다.

  • 마이크 세션은 input node에 tap을 설치합니다.
  • 가져온 파일과 완료된 로컬 녹음은 AVAudioPlayerNode에서 재생하고, main mixer tap에서 실제 재생 경로를 분석합니다.
  • 녹음은 마이크 input tap을 라이브 분석과 공유하고, 수락한 buffer를 파일 기록기에 전달합니다.
  • Demo는 권한을 요청하지 않고 결정적인 ScopeFrame을 생성합니다.

중요한 것은 전송 코드가 완전히 같다는 점이 아니라, 실제 오디오가 마지막에는 같은 분석 계약으로 들어간다는 점입니다. 계약은 Float32 모노 창, sample rate, route fingerprint, channel count입니다.

멀티채널 입력은 명시된 모노 분석 신호로 fold-down 됩니다. 이 덕분에 스펙트럼과 라우드니스가 일관되지만, 멀티채널 납품 미터를 가장하지는 않습니다. UI는 채널 수를 숨기지 않습니다. route나 sample rate가 바뀌면 분석기는 상태를 재설정하고 대역 범위를 다시 구성합니다. 이전 Integrated loudness나 FFT 범위를 새 입력으로 가져오면 연속적으로 보여도 일관된 세션이 아니기 때문입니다.

render thread의 일을 제한한다

AVAudioEngine tap은 오디오 렌더링 경로 가까이에 있습니다. 뷰 업데이트를 기다리거나, 네트워크를 시작하거나, 무한 이력을 추가하거나, 세션 길이에 비례하는 buffer를 할당할 자리가 아닙니다.

SignalMetric은 고정된 2,048 샘플 창을 모으고 두 개의 미리 할당된 sample slot을 사용합니다. 하나는 직렬 분석 중일 수 있고, 하나는 대기할 수 있습니다. 창이 차면 캡처 경로는 사용 가능한 slot에 복사하고 한 번의 분석을 예약합니다. 이미 대기 창이 있으면 그 뒤에 더 넣지 않습니다. 화면을 여러 초 전의 값으로 만들지 않기 위해 지연 부채를 만들지 않는 선택입니다.

Sequence diagram Preparing diagram
View diagram source
sequenceDiagram
    participant Tap as Audio tap
    participant Capture as 고정 캡처 슬롯
    participant Analyzer as 직렬 분석기
    participant Store as 최신 프레임 잠금
    participant UI as Main actor 30 FPS

    Tap->>Capture: 2,048 샘플 창 채우기
    alt 대기 프레임 없음
        Capture->>Analyzer: 하나의 창 예약
        Analyzer->>Analyzer: FFT, 레벨, 라우드니스, 파형
        Analyzer->>Store: 최신 ScopeFrame 교체
    else 대기 프레임 있음
        Capture-->>Capture: backlog를 늘리지 않음
    end
    UI->>Store: 최신 완료 프레임 읽기
    Store-->>UI: 일관된 하나의 snapshot
    UI->>UI: 네 workspace 렌더링

UI는 main actor에서 30 FPS로 가장 최근에 끝난 프레임을 읽습니다. 오디오 콜백은 SwiftUI를 직접 호출하지 않습니다. 표시 cadence는 안정적으로 유지하면서 callback cadence는 장치 route와 I/O buffer에 따를 수 있습니다.

최신 프레임은 lock으로 보호되어 하나의 값으로 교체됩니다. Monitor의 수치가 한 FFT 창에 속하고 Scope의 파형이 다른 창에 속하는 일은 없습니다. 화면은 한 프레임 늦을 수 있어도 내부는 일관됩니다.

프레임 안에 담기는 증거

ScopeFrame은 신호 처리와 표현 사이의 경계입니다. 여기에는 다음이 들어갑니다.

  • raw RMS dBFS, smoothed display level, instantaneous Sample Peak, peak hold, 4x True Peak estimate;
  • K-weighted Momentary, Short-Term, Integrated loudness, LRA;
  • 24개 표시 대역, 64개 로그 dBFS trace, peak hold, 스펙트럼 통계;
  • 강한 스펙트럼 성분, centroid, bandwidth, 85% roll-off, flatness;
  • 트리거된 256 bin waveform envelope;
  • DC offset, zero-crossing rate, channel count, clip state, dominant frequency, beat confidence;
  • sample rate, source fingerprint, timestamp, analysis window 기간.

단위 형식, 색상, 화면별 규칙은 이 모델에 넣지 않습니다. 분석기는 신호 증거를 소유하고, ViewModel은 형식화된 단위, 선택 workspace, 접근성 요약, response preference, session reset, 상한이 있는 30초 이력을 다룹니다. UI 변경이 측정 자체를 조용히 바꾸지 않도록 하기 위해서입니다.

FFT만이 전부는 아니다

분석기는 Hanning 창 뒤에서 Accelerate/vDSP로 2,048 point DFT를 실행합니다. Hanning 창은 leakage를 줄이지만, 눈에 띄는 bin이 곧바로 정확한 중심 주파수의 완벽한 사인파를 뜻하지는 않습니다.

강한 성분 표시는 다음을 수행합니다.

  1. 절대 및 상대 floor를 넘는 로컬 최대값을 찾습니다.
  2. 분해 가능한 Hanning main-lobe 이웃 후보를 억제하여 한 성분이 여러 side-lobe card가 되지 않게 합니다.
  3. log magnitude 포물선 보간으로 주파수를 세밀하게 합니다.
  4. Hanning coherent gain을 보정하여 레벨을 표시합니다.
  5. 두 개 이상의 피크가 같은 후보 fundamental을 지지할 때만 harmonic label을 붙입니다.
  6. 더 낮은 게시 cadence에서 성분을 대응시키고 부드럽게 하여 순위 깜빡임을 피합니다.

따라서 Spectrum은 주파수 증거를 읽기 쉽게 하지만, 여섯 사인파가 소스 전체를 재구성했다고 말하지 않습니다. 원시 분해능은 sampleRate / 2048로 공개됩니다.

레벨과 라우드니스에도 같은 절제가 적용됩니다. RMS와 Sample Peak는 실용적인 디지털 범위에 두고 True Peak는 estimate로 명시합니다. 라우드니스는 지속적인 K-weighting과 시간 가중 창을 사용합니다. Momentary는 400 ms, Short-Term은 3초, Integrated는 100 ms hop의 400 ms block과 절대·상대 게이트를 사용합니다. 이는 BS.1770-style 모노 분석이지 인증된 납품 컴플라이언스 주장이 아닙니다.

이력도 상한이 있어야 한다

좋은 Timeline은 연속적으로 느껴져야 하지만 메모리 예산은 고정되어야 합니다. SignalMetric은 스펙트럼 이력을 초당 8프레임으로 게시하고 30초 동안 최대 240열을 유지합니다. 세션 시작부터 모든 분석 프레임을 보관하지 않습니다.

Scope도 같습니다. 숨겨진 고해상도 녹음이 아니라 상승 zero-crossing trigger 이후 현재 창을 고정 256 bin min/max/average envelope로 축소합니다. 좁은 트랜지언트는 각 bin의 min/max로 남고 표시 비용도 예측 가능합니다.

Flow diagram Preparing diagram
View diagram source
flowchart TD
    A[원본 소스 프레임] --> B[고정 2,048 샘플 분석 창]
    B --> C[64 로그 대역 스펙트럼]
    C --> D[초당 8프레임 이력 게시]
    D --> E[240열 Timeline]
    B --> F[트리거 뒤 축소]
    F --> G[256 bin 파형 엔벌로프]
    E --> H[일정한 세션 메모리]
    G --> H

이것은 성능 최적화만은 아닙니다. 무한 이력은 메모리와 렌더 비용을 시간에 따라 바꾸고 긴 세션을 다른 도구로 만듭니다. 계기는 한 시간 뒤에도 같은 계기여야 합니다.

녹음은 두 번째 실시간 책임이다

녹음은 시간에 민감한 입력 경로에 disk I/O를 더합니다. 원본 AVAudioPCMBuffer를 느린 writer에 직접 넘기면 저장 압력이 캡처에 연결됩니다. SignalMetric은 수락한 buffer를 복사해 전용 직렬 queue에서 기록합니다.

대기 녹음 buffer는 최대 64개입니다. 저장이 따라오지 못하면 메모리를 무한히 늘리는 대신 녹음을 중단합니다. Stop, interruption, route change, background가 발생하면 먼저 새 buffer를 거부하고 수락된 기록을 비운 뒤 로컬 M4A를 닫습니다. main thread는 기다리지 않습니다.

State diagram Preparing diagram
View diagram source
stateDiagram-v2
    [*] --> LiveAnalysis
    LiveAnalysis --> Recording: Record 탭
    Recording --> Finalizing: Stop / interruption / background
    Finalizing --> LocalFile: 수락된 기록을 비우고 M4A 닫기
    Finalizing --> Failed: 빈 파일 또는 기록 실패
    LocalFile --> FileAnalysis: 로컬 녹음 열기
    FileAnalysis --> LiveAnalysis: 소스 전환

일반 Live Mic은 메모리 분석으로 남습니다. 파일은 사용자가 Record를 탭한 뒤에만 생성되며, 사용자가 공유 대상을 고르기 전까지 로컬에 있습니다.

한계도 설계의 일부다

SignalMetric은 편리해 보이는 몇 가지 지름길을 피합니다.

  • 오디오 callback에서 SwiftUI를 호출하지 않습니다.
  • queue나 history가 세션 길이에 따라 자라지 않습니다.
  • 마이크나 가져온 오디오를 처리 목적으로 upload하지 않습니다.
  • 보정되지 않은 마이크 수치를 SPL로 포장하지 않습니다.
  • 4x 샘플 사이 estimate를 인증 결과라고 부르지 않습니다.
  • confidence가 낮은 tempo나 pitch를 억지로 표시하지 않습니다.

결과는 서로 무관한 네 애니메이션이 아닙니다. 하나의 소스, 하나의 분석 경계, 더 나은 질문을 위한 네 가지 보기입니다. 사용자 관점의 전체 지도는 SignalMetric 제품 가이드에서 확인할 수 있습니다.

MonoWare에서

SignalMetric에는 이 노트의 더 많은 맥락이 있습니다.

제품 사이트를 열거나 SignalMetric로 필터된 노트를 계속 읽으세요.

뉴스레터

개인정보와 제품 엔지니어링 노트를 가끔 보내드립니다.