Skip to content

Latest commit

 

History

History
256 lines (204 loc) · 61.3 KB

File metadata and controls

256 lines (204 loc) · 61.3 KB

DirectPipe Architecture / 아키텍처

Version 4.0.3 / 버전 4.0.3

System Overview / 시스템 개요

DirectPipe is a real-time VST2/VST3 host that processes microphone input through a plugin chain. It provides three independent output paths: main output to the AudioSettings device (WASAPI/ASIO on Windows, CoreAudio on macOS, ALSA/JACK on Linux), optional monitor output to headphones (separate audio device), and IPC output to shared memory for the Receiver VST2 plugin (e.g., OBS). Processed audio can also be recorded to WAV. All external control sources (hotkeys, MIDI, WebSocket, HTTP, Stream Deck) funnel through a unified ActionDispatcher. Platform support: Windows (stable), macOS (beta), Linux (experimental).

DirectPipe는 마이크 입력을 VST 플러그인 체인으로 실시간 처리하는 VST 호스트다. 3가지 독립 출력 경로 제공: 메인 출력(AudioSettings 장치, Windows: WASAPI/ASIO, macOS: CoreAudio, Linux: ALSA/JACK), 모니터 출력(헤드폰, 별도 오디오 장치), IPC 출력(공유 메모리 → Receiver VST2, 예: OBS). 처리된 오디오의 WAV 녹음도 지원. 모든 외부 제어(단축키, MIDI, WebSocket, HTTP, Stream Deck)는 ActionDispatcher를 통해 통합된다. 플랫폼 지원: Windows (안정), macOS (베타), Linux (실험적).

Mic ─→ Audio Driver ─→ Input Gain ─→ VST2/VST3 Plugin Chain ─┐
        (WASAPI/ASIO [Win],                        Global Safety Guard
         CoreAudio [macOS],                                    │
         ALSA/JACK [Linux])                                    │
                 ┌────────────────────────────────────────────┼────────────────────┐
                 │                                            │                    │
           Main Output                                  Monitor Output         IPC Output
        (outputChannelData)                           (OutputRouter →         (SharedMemWriter →
     Audio tab Output device                         MonitorOutput,       Shared Memory →
     e.g. VB-Cable → Discord                        separate audio       OBS [Receiver VST2])
                 │                                    device → Headphones)
           AudioRecorder → WAV File

External Control:
  Hotkey / MIDI / Stream Deck / WebSocket (:8765) / HTTP (:8766)
    → ControlManager → ActionDispatcher
      → VSTChain (bypass/params), OutputRouter (volume), PresetManager (slots),
        AudioRecorder (recording), SharedMemWriter (IPC toggle)

Design choices / 설계 원칙:

  • WASAPI Shared (Windows) — Non-exclusive mic access. Other apps can use the mic simultaneously. / (Windows) 비독점 마이크 접근. 다른 앱과 동시 사용 가능.
  • ASIO (Windows) — Lower latency for ASIO-compatible interfaces. / (Windows) ASIO 호환 인터페이스로 저지연.
  • CoreAudio (macOS) — Native low-latency audio driver. / (macOS) 네이티브 저지연 오디오 드라이버.
  • ALSA/JACK (Linux) — ALSA for direct hardware access, JACK for pro audio routing. / (Linux) ALSA: 직접 하드웨어 접근, JACK: 프로 오디오 라우팅.
  • Runtime switching between driver types. UI adapts dynamically. / 드라이버 타입 런타임 전환. UI 자동 적응.
  • 3 output paths (independently controlled) — Main output directly to AudioSettings device (e.g., VB-Audio for Discord). Monitor uses a separate audio device for headphones. IPC output sends to shared memory for Receiver VST2 plugin (e.g., OBS — no virtual cable needed). Each path can be independently toggled and volume-adjusted via OUT/MON/VST buttons or external controls (hotkey, MIDI, Stream Deck, HTTP). This enables scenarios like muting the OBS stream mic (VST OFF) while keeping Discord active (OUT ON), or vice versa. Panic Mute (Ctrl+Shift+M) kills all outputs instantly; previous states auto-restore on unmute. / 3가지 독립 출력: 메인(AudioSettings 장치), 모니터(별도 오디오 장치, 헤드폰), IPC(공유 메모리 → Receiver VST2, 가상 케이블 불필요). 각 경로는 OUT/MON/VST 버튼 또는 외부 제어로 개별 ON/OFF 및 볼륨 조절 가능. OBS 마이크만 끄고 Discord 유지, 또는 반대도 가능. 패닉 뮤트로 전체 즉시 차단 + 해제 시 이전 상태 복원.
  • 19 actions — Unified action system: PluginBypass, MasterBypass, SetVolume, ToggleMute, LoadPreset, PanicMute, InputGainAdjust, NextPreset, PreviousPreset, InputMuteToggle, SwitchPresetSlot, MonitorToggle, RecordingToggle, SetPluginParameter, IpcToggle, XRunReset, SafetyLimiterToggle, SetSafetyLimiterCeiling, AutoProcessorsAdd. / 19개 통합 액션 시스템.

Components / 컴포넌트

1. Host Application (host/) / 호스트 앱

JUCE 7.0.12-based desktop application. Main audio processing engine.

JUCE 7.0.12 기반 데스크톱 앱. 메인 오디오 처리 엔진.

Audio Module (host/Source/Audio/) / 오디오 모듈

  • AudioEngineWindows: 5 driver types — DirectSound (legacy), Windows Audio (WASAPI Shared, recommended), Windows Audio (Low Latency) (IAudioClient3), Windows Audio (Exclusive Mode), ASIO. macOS: CoreAudio. Linux: ALSA, JACK. Manages the audio device callback. Pre-allocated work buffers (8ch). Mono mixing or stereo passthrough. Runtime device type switching, sample rate/buffer size queries. Input gain (atomic), master mute. Audio optimizations: ScopedNoDenormals (prevents CPU spikes from denormals in VST plugins), muted fast-path (skips VST chain when muted), RMS decimation (every 4th callback). Rolling 60-second XRun monitoring with atomic reset flag (xrunResetRequested_) for thread-safe device→message thread communication. XRun history persists through device restarts — display shows full 60s window regardless of device state changes. setBufferSize auto-fallback to closest device-supported size with notification. Device auto-reconnection: Dual mechanism — ChangeListener on deviceManager_ for immediate detection + 3s timer polling fallback. Tracks desiredInputDevice_/desiredOutputDevice_. Preserves SR/BS/channel routing on reconnect. Per-direction loss: inputDeviceLost_ zeroes input in audio callback, outputAutoMuted_ auto-mutes/unmutes output. reconnectMissCount_ accepts current devices after 5 failed attempts only for cross-driver stale name scenarios; when outputAutoMuted_ is true (genuine device loss / physical unplug), the counter resets and keeps waiting indefinitely for the desired device. setInputDevice/setOutputDevice clear deviceLost_, inputDeviceLost_, outputAutoMuted_, and reconnection counters — allows users to manually select a different device during device loss without waiting for reconnection. Driver type snapshot: DriverTypeSnapshot saves per-driver settings (input/output device, SR, BS, outputNone) before type switch, restores when switching back. outputNone_ cleared on driver type switch (prevents OUT mute lock after WASAPI "None" -> ASIO), restored from snapshot if the target driver had it saved. ipcAllowed_ blocks IPC in audio-only multi-instance mode. Audio optimizations (timeBeginPeriod, Power Throttling disable, MMCSS "Pro Audio" thread registration at AVRT_PRIORITY_HIGH) are Windows-specific; macOS/Linux rely on JUCE defaults. Output "None" mode: setOutputNone(bool) / isOutputNone()outputNone_ atomic flag mutes output and locks OUT button (intentional "no output device" state, similar to panic mute lockout but for deliberate use). Cleared on driver type switch to prevent OUT button lock persisting across drivers. DriverTypeSnapshot saves/restores outputNone per driver type. ASIO SR/BS policy: ASIO devices own SR/BS globally (affects all apps sharing the device). On startup, DirectPipe does NOT force saved SR/BS on ASIO — instead accepts whatever the device currently reports via syncDesiredFromDevice(). Reason: forcing SR/BS would restart the ASIO driver, disrupting audio in DAWs, media players, and other apps. When the user changes BS from the ASIO control panel, audioDeviceAboutToStart syncs desiredSR/desiredBS from the device, and the new values are automatically saved to settings. WASAPI/CoreAudio/ALSA use per-app SR/BS, so saved values are safely forced on startup (no impact on other apps). Startup flow: Always opens WASAPI first (safe fallback), then loads saved driver type from settings and switches to ASIO if configured. The WASAPI→ASIO transition typically completes before the window is shown (~100ms in common cases). Falls back to WASAPI if ASIO driver is unavailable. / Windows 5종 드라이버, macOS CoreAudio, Linux ALSA/JACK. 오디오 콜백 관리. 사전 할당 버퍼. Mono/Stereo 처리. 입력 게인, 마스터 뮤트, RMS 레벨 측정. 장치 자동 재연결: 듀얼 감지 + 방향별 감지 (입력/출력 분리). reconnectMissCount_는 교차 드라이버 이름 불일치에만 폴백 적용; outputAutoMuted_ true(물리적 분리)시 원하는 장치를 무기한 대기. setInputDevice/setOutputDevice는 장치 손실 중 수동 선택을 허용하기 위해 deviceLost_ 및 재연결 카운터를 초기화. 드라이버 타입 스냅샷: 타입 전환 시 설정 저장/복원 (outputNone 포함). outputNone_는 드라이버 전환 시 초기화, 스냅샷에서 복원. ipcAllowed_로 audio-only 모드에서 IPC 차단. Output "None" 모드: setOutputNone(bool) / isOutputNone()outputNone_ atomic 플래그로 출력 뮤트 + OUT 버튼 잠금 (의도적 "출력 장치 없음" 상태). 드라이버 전환 시 초기화, DriverTypeSnapshot으로 드라이버별 저장/복원. ASIO SR/BS 정책: ASIO 장치는 SR/BS를 전역으로 소유 (장치를 공유하는 모든 앱에 영향). 시작 시 저장된 SR/BS를 ASIO에 강제하지 않고, syncDesiredFromDevice()를 통해 장치가 보고하는 현재 값을 수용. 이유: SR/BS 강제 시 ASIO 드라이버 재시작 → DAW, 미디어 플레이어 등 다른 앱의 오디오 끊김. ASIO 컨트롤 패널에서 BS 변경 시 audioDeviceAboutToStartdesiredSR/desiredBS를 장치에서 동기화하여 설정에 자동 반영. WASAPI/CoreAudio/ALSA는 앱별 SR/BS이므로 시작 시 저장된 값을 안전하게 강제 적용 (다른 앱에 영향 없음). 시작 흐름: WASAPI로 먼저 시작 (안전한 폴백) → 설정 파일에서 저장된 드라이버 타입 로드 → ASIO 설정 시 전환 시도. WASAPI→ASIO 전환은 일반적으로 창 표시 전에 끝나지만, 시스템 환경에 따라 달라질 수 있음. ASIO 드라이버 사용 불가 시 WASAPI에 남아있음.
  • VSTChainAudioProcessorGraph-based VST2/VST3 plugin chain. rebuildGraph(bool suspend = true) rebuilds connections — suspend=true (default) for node add/remove, suspend=false for bypass toggle (connection-only change, avoids a full chain reload). Bypassed plugins are disconnected from the signal chain in rebuildGraph (audio routes around them). setPluginBypassed syncs both node->setBypassed() and getBypassParameter()->setValueNotifyingHost() for plugins with internal bypass parameter (VST2 canDo("bypass"), VST3), then calls rebuildGraph(false). Async chain replacement (replaceChainAsync) loads plugins on background thread with alive_ flag (shared_ptr<atomic<bool>>) to guard callAsync completion callbacks against object destruction. Keep-Old-Until-Ready: old chain continues processing audio during background plugin loading; new chain swapped atomically on message thread when ready (often around ~10-50ms under typical cache-hit or light-load conditions, vs previous 1-3s mute gap). asyncGeneration_ counter discards stale callAsync callbacks from superseded loads. Batch graph rebuild via UpdateKind::async for intermediate addNode/removeNode calls (N² → O(1) rebuild count). Editor windows tracked per-plugin. Pre-allocated MidiBuffer. chainLock_ (mutable CriticalSection) protects ALL reader methods (getPluginSlot, getPluginCount, setPluginBypassed, parameter access, editor open/close) — not just writers. prepared_ is std::atomic<bool> for RT-safe access. processBlock uses capacity guard instead of misleading buffer size check. movePlugin resizes editorWindows_ before move to prevent out-of-bounds access. / VST2/VST3 플러그인 체인. Keep-Old-Until-Ready: 백그라운드 플러그인 로딩 중 이전 체인이 오디오 처리를 유지, 메시지 스레드에서 원자적 스왑 (캐시 히트나 가벼운 로드 조건에서는 흔히 ~10-50ms 수준이지만 상황에 따라 달라질 수 있으며, 이전 1-3초 무음 대비 크게 개선). asyncGeneration_ 카운터로 대체된 로드의 stale callAsync 콜백 폐기. UpdateKind::async로 배치 그래프 리빌드. alive_ 플래그(shared_ptr<atomic<bool>>)로 callAsync 콜백의 수명 안전 보장. MidiBuffer 사전 할당. chainLock_ (mutable CriticalSection)이 모든 리더 메서드도 보호. prepared_std::atomic<bool>. processBlock은 용량 가드 사용. movePlugin은 이동 전 editorWindows_ 크기 조정. Known limitation: bypassing a reverb/delay plugin immediately cuts its tail (graph disconnection). Future: consider dry-input routing while continuing processBlock for natural tail decay. / 알려진 제한사항: 리버브/딜레이 플러그인 바이패스 시 잔향 테일 즉시 절단 (그래프 연결 해제). 향후: processBlock 유지하면서 dry 입력 라우팅 검토.
  • OutputRouter — Routes processed audio to the monitor output (separate audio device). Independent atomic volume and enable controls. Pre-allocated scaled buffer. routeAudio() clamps numSamples to scaledBuffer_ capacity (prevents buffer overrun). Main output goes directly through outputChannelData. / 모니터 출력(별도 오디오 장치)으로 오디오 라우팅. routeAudio()numSamplesscaledBuffer_ 용량에 클램프 (버퍼 오버런 방지). 메인 출력은 outputChannelData로 직접 전송.
  • MonitorOutput — Second AudioDeviceManager used for the monitor output (WASAPI on Windows, CoreAudio on macOS, ALSA/JACK on Linux). Lock-free AudioRingBuffer bridge between two audio callback threads. Configured in Output tab. Status tracking (Active/Error/NotConfigured/SampleRateMismatch). Independent auto-reconnection via monitorLost_ atomic + 3s timer polling. / 모니터 출력용 별도 AudioDeviceManager (Windows: WASAPI, macOS: CoreAudio, Linux: ALSA). 락프리 링버퍼 브리지. Output 탭에서 구성. 상태 추적. monitorLost_ + 3초 타이머로 독립 자동 재연결.
  • PluginPreloadCache — Background pre-loads other slots' plugin instances after slot switch. Cache hit = fast swap (often around ~10-50ms in typical cases, vs 200-500ms class DLL loading on cache miss). Invalidated on SR/BS change, slot structure change (plugin names/paths/order via isCachedWithStructure), slot delete/copy. Per-slot version counter (slotVersions_) prevents stale preload: version captured at file-read time, checked before cache store — discards results if invalidateSlot was called mid-preload. Max 5 slots × ~4 plugins cached. / 슬롯 전환 후 다른 슬롯의 플러그인 인스턴스를 백그라운드 프리로드. 캐시 hit = 빠른 스왑 (일반적인 경우 흔히 ~10-50ms 수준이지만, 캐시 미스나 플러그인 상태에 따라 더 길어질 수 있음). SR/BS 변경, 슬롯 구조 변경(플러그인 이름/경로/순서, isCachedWithStructure), 슬롯 삭제/복사 시 무효화. Per-slot 버전 카운터(slotVersions_)로 stale 프리로드 방지: 파일 읽기 시점에 버전 캡처, 캐시 저장 전 확인 — 프리로드 중 invalidateSlot 호출되면 결과 폐기.
  • AudioRingBuffer — Header-only SPSC lock-free ring buffer for inter-device audio transfer. reset() zeroes all channel data. / 디바이스 간 오디오 전송용 헤더 전용 SPSC 락프리 링 버퍼. reset()은 모든 채널 데이터를 0으로 초기화.
  • LatencyMonitor — High-resolution timer-based latency measurement. Callback overrun detection (getCallbackOverrunCount()) — processing time exceeding buffer period guarantees an audio glitch. / 고해상도 타이머 기반 레이턴시 측정. 콜백 오버런 감지 (getCallbackOverrunCount()) — 처리 시간이 버퍼 주기를 초과하면 오디오 글리치 발생.
  • AudioRecorder — Lock-free audio recording to WAV via AudioFormatWriter::ThreadedWriter. SpinLock-protected writer teardown for RT-safety. Timer-based duration tracking. Auto-stop on device change. outputStream properly deleted on writer creation failure (leak fix). / 락프리 WAV 녹음. SpinLock으로 RT 안전한 writer 해제. 장치 변경 시 자동 중지. writer 생성 실패 시 outputStream 올바르게 삭제 (누수 수정).
  • SafetyLimiter — RT-safe brickwall-style limiter (2ms look-ahead, instant attack, 50ms release, hard ceiling clamp). Inserted after VSTChain, before all output paths. Atomic params: enabled, ceilingdB. GR feedback via atomic for UI. / RT 안전 브릭월 스타일 리미터. VSTChain 이후, 모든 출력 경로 이전에 삽입. Atomic 파라미터.
  • DeviceState — Enum-based state machine for device connection status. Replaces multiple boolean flags with explicit states for switch-based handling. Compiler warns on missing cases. / 장치 연결 상태를 위한 enum 기반 상태 머신. 다수의 boolean 플래그 대신 명시적 상태로 switch 처리. 컴파일러가 누락된 case 경고.
  • BuiltinFilter — HPF+LPF audio processor (AudioProcessor subclass). Inserted into AudioProcessorGraph alongside VSTs. HPF default ON 60Hz, LPF default OFF 16kHz. Supports mono + stereo. / HPF+LPF 오디오 프로세서 (AudioProcessor 서브클래스). VST와 함께 AudioProcessorGraph에 삽입.
  • BuiltinNoiseRemoval — RNNoise-based noise suppression (AudioProcessor subclass). 48kHz only, 480-frame FIFO (~10ms latency), dual-mono. VAD gate with configurable threshold. / RNNoise 기반 노이즈 제거 (AudioProcessor 서브클래스). 48kHz 전용, 480프레임 FIFO, 듀얼 모노. VAD 게이트.
  • BuiltinAutoGain — LUFS-based automatic gain control (AudioProcessor subclass). WebRTC-inspired dual-envelope level detection (fast 10ms/200ms + slow 0.4s LUFS, max selection) with direct gain computation (no IIR gain envelope). K-weighting ITU-R BS.1770 sidechain. Incremental runningSquareSum_. Configurable target LUFS, lowCorr/hiCorr (hold↔full correction blend), max gain 22dB, freeze gate (holds current gain during silence). -6dB internal target offset for open-loop overshoot compensation. / LUFS 기반 자동 게인 제어 (AudioProcessor 서브클래스). WebRTC 영감의 듀얼 엔벨로프 레벨 감지 (fast 10ms/200ms + slow 0.4s LUFS) + 직접 게인 연산 (IIR 게인 엔벨로프 없음). K-weighting ITU-R BS.1770 사이드체인. 증분식 runningSquareSum_. freeze 게이트: 무음 시 현재 게인 유지.
  • PluginLoadHelper — Helper for cross-platform VST loading. Abstracts platform-specific plugin loading paths and formats. / 크로스 플랫폼 VST 로딩 헬퍼. 플랫폼별 플러그인 로딩 경로와 포맷을 추상화.

Control Module (host/Source/Control/) / 제어 모듈

All external inputs funnel through a unified ActionDispatcher. / 모든 외부 입력은 통합된 ActionDispatcher를 거친다.

  • ActionResult (ActionResult.h) — Typed success/failure return value for action and device operations. static ok() / static fail(msg), explicit operator bool(), message propagation. Used by AudioEngine device methods and ActionHandler. / 액션 및 장치 작업의 타입화된 성공/실패 반환값. AudioEngine 장치 메서드와 ActionHandler에서 사용.
  • ActionHandler — Centralized action event handling, extracted from MainComponent. Receives ActionEvent from ActionDispatcher and routes to AudioEngine, VSTChain, PresetManager, OutputRouter, etc. doPanicMute(bool) consolidates panic mute logic: saves pre-mute state (monitor, output mute, IPC), mutes output paths, stops active recording. On unmute, restores previous state (recording does not auto-restart). Most action cases check engine_.isMuted() to block during panic. Guard bypass actions: PanicMute, InputMuteToggle, XRunReset, SafetyLimiterToggle, SetSafetyLimiterCeiling, AutoProcessorsAdd. Callback-based decoupling from MainComponent (onDirty, onNotification, onPanicStateChanged, onRecordingStopped, etc.). / MainComponent에서 추출된 중앙 액션 이벤트 처리. doPanicMute(bool)가 패닉 뮤트 로직 통합: pre-mute 상태 저장, 출력 경로 차단, 녹음 중지. 해제 시 이전 상태 복원 (녹음은 자동 재시작 안 함). 대부분의 액션은 isMuted() 체크로 패닉 중 차단되며, 예외 액션은 PanicMute/InputMuteToggle/XRunReset/SafetyLimiterToggle/SetSafetyLimiterCeiling/AutoProcessorsAdd.
  • SettingsAutosaver — Dirty-flag + 1-second debounce auto-save logic, extracted from MainComponent. Monitors onSettingsChanged callbacks and triggers periodic save. / MainComponent에서 추출된 dirty-flag + 1초 디바운스 자동 저장 로직.
  • ActionDispatcher — Central action routing. 19 actions: PluginBypass, MasterBypass, SetVolume, ToggleMute, LoadPreset, PanicMute, InputGainAdjust, NextPreset, PreviousPreset, InputMuteToggle, SwitchPresetSlot, MonitorToggle, RecordingToggle, SetPluginParameter, IpcToggle, XRunReset, SafetyLimiterToggle, SetSafetyLimiterCeiling, AutoProcessorsAdd. Thread-safe dispatch via callAsync with alive_ flag (shared_ptr<atomic<bool>>) lifetime guard. Copy-before-iterate for reentrant safety. actionToString() helper for enum-to-string conversion. Dispatched actions logged as [ACTION] (high-frequency excluded). Note: XRunReset via HTTP bypasses ActionDispatcher (direct engine_.requestXRunReset() call); all other actions route through ActionDispatcher from both HTTP and WebSocket. / 중앙 액션 라우팅. 19개 액션. alive_ 플래그로 수명 보호된 callAsync 디스패치. 재진입 안전을 위한 copy-before-iterate. actionToString() 헬퍼로 enum→문자열 변환. 디스패치된 액션 [ACTION] 로그 (고빈도 제외). 참고: XRunReset은 HTTP에서 ActionDispatcher를 우회하여 engine_.requestXRunReset()을 직접 호출. 나머지 액션은 HTTP/WebSocket 모두 ActionDispatcher 경유.
  • ControlManager — Aggregates all control sources (Hotkey, MIDI, WebSocket, HTTP). Initialize/shutdown lifecycle. / 모든 제어 소스 통합 관리.
  • HotkeyHandler — Global keyboard shortcuts. Windows: RegisterHotKey API. macOS: CGEventTap (requires Accessibility permission — notifies user via onError callback if not granted). Linux: stub (not yet supported — HotkeyTab shows "unsupported" message). Recording mode for key capture. onError callback for non-fatal errors (e.g., missing macOS accessibility permission). / 글로벌 키보드 단축키. Windows: RegisterHotKey API. macOS: CGEventTap (접근성 권한 필요 — 미허용 시 onError 콜백으로 사용자 알림). Linux: 스텁 (미지원 — HotkeyTab에 "unsupported" 메시지 표시). 키 녹화 모드. onError 콜백으로 비치명적 오류 전달.
  • MidiHandler — JUCE MidiInput for MIDI CC/note mapping with Learn mode. LED feedback via MidiOutput. Hot-plug detection. bindingsMutex_ protects all access to bindings_; getBindings() returns a copy for safe iteration. processCC/processNote collect matching actions into a local vector, then dispatch OUTSIDE bindingsMutex_ (deadlock prevention). / MIDI CC 매핑 + Learn 모드. LED 피드백. 핫플러그 감지. bindingsMutex_bindings_ 접근 보호; getBindings()는 안전한 반복을 위해 복사본 반환. processCC/processNote는 매칭 액션을 로컬 벡터에 수집 후 bindingsMutex_ 밖에서 디스패치 (교착 방지).
  • WebSocketServer — RFC 6455 WebSocket server (port 8765). Custom SHA-1 implementation for handshake. Case-insensitive HTTP header matching (RFC 7230 compliance). JUCE StreamingSocket with frame encoding/decoding, ping/pong. Dead client cleanup — sendFrame returns bool, broadcastToClients closes socket immediately on write failure (prevents repeated write-error log spam from stale clients). UDP discovery broadcast on port 8767 at startup for instant Stream Deck connection. broadcastToClients releases clientsMutex_ before socket writes (prevents global lock contention during slow-client writes) and joins dead client threads outside lock to prevent deadlock. Sends RFC 6455 close frame (1009) before disconnecting oversized-message clients. / RFC 6455 WebSocket 서버. 커스텀 SHA-1 핸드셰이크. 대소문자 무시 HTTP 헤더 매칭 (RFC 7230 준수). sendFramebool 반환, broadcastToClients가 쓰기 실패 시 소켓 즉시 닫음 (stale 클라이언트 반복 오류 로그 방지). 시작 시 UDP 8767 디스커버리 브로드캐스트로 Stream Deck 즉시 연결. broadcastToClients는 소켓 쓰기 전에 clientsMutex_를 해제해 느린 클라이언트 쓰기 시 전역 락 경합을 줄이고, dead client 스레드 join은 잠금 밖에서 수행해 교착을 방지. 과대 메시지 클라이언트 연결 해제 시 RFC 6455 close frame (1009) 전송.
  • HttpApiServer — HTTP REST API (port 8766) for one-shot GET commands. CORS enabled with OPTIONS preflight support (Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS) for browser-based clients. 3-second read timeout. Input validation: strict parseFloat() using strtof with end-pointer check — rejects mixed alpha-numeric input like "abc0.5" that getFloatValue() silently converts to 0.0. Volume/parameter values range-checked. JSON responses escape special characters. Gain delta endpoint scales by 10× to compensate for ActionHandler's *0.1f hotkey step design. Proper HTTP status codes (404 Not Found, 405 Method Not Allowed, 400 Bad Request) — processRequest returns pair<int, string>. Safety Limiter ceiling endpoint validates range (-6.0 to 0.0 dBFS). Recording toggle, plugin parameter, IPC toggle, MIDI test injection endpoints. / HTTP REST API. CORS preflight (OPTIONS) 지원. 3초 읽기 타임아웃. 입력 검증: 엄격한 parseFloat()strtof + 엔드 포인터 검사로 "abc0.5" 같은 혼합 문자열 거부. JSON 응답에서 특수 문자 이스케이프. 게인 델타는 ActionHandler의 *0.1f 스케일링 보정을 위해 10× 스케일링. Safety Limiter ceiling은 -6.0~0.0 dBFS 범위 검증. 적절한 HTTP 상태 코드 (404/405/400).
  • StateBroadcaster — Pushes AppState changes to all connected StateListeners as JSON. Includes ipc_enabled, device_lost, monitor_lost, slot_names, output_muted fields in state object. quickStateHash dirty-flag skips JSON serialization + broadcast when state unchanged. Thread-safe: state updates from any thread, listeners always notified on message thread via callAsync with alive_ flag lifetime guard. Copy-before-iterate for reentrant safety. WebSocket broadcast on dedicated thread (non-blocking). Notification queue: uint32_t indices (overflow-safe), capacity guard before write. / 상태 변경을 JSON으로 모든 리스너에 푸시. 상태 객체에 ipc_enabled 필드 포함. 스레드 안전: 어느 스레드에서든 상태 업데이트 가능, alive_ 플래그로 수명 보호된 callAsync 리스너 알림. 재진입 안전을 위한 copy-before-iterate. WebSocket 브로드캐스트 전용 스레드 (비차단). 알림 큐: uint32_t 인덱스 (오버플로 안전), 쓰기 전 용량 가드.
  • DirectPipeLogger — Centralized logging system. Captures logs from all subsystems (audio engine, plugins, WebSocket, HTTP, etc.). Feeds LogPanel and NotificationBar. Ring buffer indices use uint32_t (overflow-safe). All log messages use category tags: [APP], [AUDIO], [VST], [PRESET], [ACTION], [HOTKEY], [MIDI], [WS], [HTTP], [MONITOR], [IPC], [REC], [CONTROL]. High-frequency actions (SetVolume, InputGainAdjust, SetPluginParameter) excluded from logging. / 중앙 집중 로깅 시스템. 모든 서브시스템 로그 캡처. LogPanel과 NotificationBar로 전달. 링 버퍼 인덱스 uint32_t 사용 (오버플로 안전). 모든 로그에 카테고리 태그 사용. 고빈도 액션(SetVolume, InputGainAdjust, SetPluginParameter) 로그 제외.
  • ControlMapping — JSON-based persistence for hotkey/MIDI/server config. Portable mode support (portable.flag next to exe). / JSON 기반 설정 저장. 포터블 모드 지원.
  • ControlManager — Owns and manages all external control subsystems (HotkeyHandler, MidiHandler, WebSocketServer, HttpApiServer). initialize(bool enableExternalControls) conditionally skips external control init for multi-instance audio-only mode. externalControlsActive_ flag preserved across reloadConfig()/applyConfig(). getConfigStore() provides live config access for SettingsExporter. / 모든 외부 제어 서브시스템 소유 및 관리. 다중 인스턴스 audio-only 모드를 위한 조건부 초기화. getConfigStore()로 SettingsExporter에 라이브 설정 접근 제공.

Platform Module (host/Source/Platform/) / 플랫폼 모듈

Cross-platform abstraction layer. Each sub-directory provides platform-specific implementations of a common interface. CMake conditionally compiles the correct source files per platform. / 크로스 플랫폼 추상화 계층. 각 하위 디렉토리가 공통 인터페이스의 플랫폼별 구현 제공. CMake가 플랫폼별로 올바른 소스 파일을 조건부 컴파일.

  • PlatformAudio (PlatformAudio.h, header-only) — Audio device type helpers: getDefaultSharedDeviceType() (Windows: "Windows Audio", macOS: "CoreAudio", Linux: "ALSA"), getSharedModeOutputDevices(), isExclusiveDriverType(). Replaces hardcoded WASAPI strings. / 오디오 디바이스 타입 헬퍼 (헤더 온리): 하드코딩된 WASAPI 문자열 대체.
  • AutoStart (AutoStart.h) — Auto-start interface: isAutoStartEnabled(), setAutoStartEnabled(bool) -> bool (returns success/failure), isAutoStartSupported(). Windows: Registry (HKCU\...\Run). macOS: LaunchAgent plist (atomicWriteFile for crash-safety). Linux: XDG .desktop file (atomicWriteFile for crash-safety). / 자동 시작 인터페이스. Windows: 레지스트리, macOS: LaunchAgent (crash-safe 쓰기), Linux: XDG autostart (crash-safe 쓰기). 설정 실패 시 bool 반환으로 사용자 알림.
  • ProcessPriority (ProcessPriority.h) — Process priority: setHighPriority(), restoreNormalPriority(). Windows: SetPriorityClass + timeBeginPeriod + Power Throttling. macOS: setpriority. Linux: nice. / 프로세스 우선순위 설정.
  • MultiInstanceLock (MultiInstanceLock.h) — Multi-instance coordination: acquireExternalControlPriority(), releaseExternalControlPriority(). Windows: Named Mutex. macOS/Linux: POSIX file locks. / 다중 인스턴스 외부 제어 우선순위 조정.

IPC Module (host/Source/IPC/) / IPC 모듈

  • SharedMemWriter — Writes processed audio to shared memory using the core library. / core 라이브러리를 사용해 공유 메모리에 오디오 기록.

UI Module (host/Source/UI/) / UI 모듈

  • AudioSettings — Driver type selector (platform-dependent: WASAPI/ASIO on Windows, CoreAudio on macOS, ALSA/JACK on Linux), device selection, ASIO channel routing (input/output pair, Windows only), sample rate, buffer size, channel mode (Mono/Stereo), latency display, ASIO Control Panel button (Windows only). Shows "DeviceName (Disconnected)" in input/output combos when the corresponding device is lost (input uses isInputDeviceLost(), output uses isOutputAutoMuted()). Selecting a different device during loss clears the loss state. / 오디오 설정 패널. 드라이버 타입은 플랫폼별 (Windows: WASAPI/ASIO, macOS: CoreAudio, Linux: ALSA/JACK). 장치 손실 시 입력/출력 콤보에 "DeviceName (Disconnected)" 표시. 손실 중 다른 장치를 선택하면 손실 상태가 해제됨.
  • PluginChainEditor — Drag-and-drop reordering, bypass toggle, edit button (native GUI), remove button. Safe deletion via callAsync. addPluginFromDescription uses SafePointer in callAsync lambda. / 드래그 앤 드롭 플러그인 체인 편집. callAsync를 통한 안전 삭제. addPluginFromDescription은 callAsync 람다에서 SafePointer 사용.
  • PluginScanner — Out-of-process VST scanner with auto-retry (10x) and dead man's pedal. Blacklist for crashed plugins. Real-time text search and column sorting (name/vendor/format). All 3 callAsync lambdas from background scan thread use SafePointer. / 별도 프로세스 VST 스캐너. 자동 재시도 10회. 블랙리스트. 실시간 검색 및 정렬. 백그라운드 스캔 스레드의 모든 callAsync 람다가 SafePointer 사용.
  • OutputPanel — Three sections: (1) Monitor output: device selector, volume slider, enable toggle, device status indicator (Active/Error/No device). (2) VST Receiver (IPC): enable toggle for shared memory output. (3) Recording: REC/STOP button, elapsed time, Play last recording, Open Folder, folder chooser. Default folder: Documents\DirectPipe Recordings. Recording folder persisted to recording-config.json. / 3개 섹션: (1) 모니터 출력(장치/볼륨/상태), (2) VST Receiver IPC 토글, (3) 녹음(REC/STOP/재생/폴더). 기본 폴더: Documents\DirectPipe Recordings.
  • PresetManager — Full preset save/load (JSON, .dppreset) + Quick Preset Slots A-E with custom naming (e.g., A|게임), slot copy/delete, individual slot export/import (.dppreset). Plugin state via getStateInformation()/base64. Async slot loading. / 프리셋 관리 + 퀵 슬롯 A-E (이름 지정, 복사/삭제, 개별 내보내기/가져오기). 비동기 슬롯 로딩.
  • ControlSettingsPanel — 3 sub-tabs: Hotkeys, MIDI, Stream Deck (server status). Each tab is a separate class: HotkeyTab, MidiTab, StreamDeckTab. MIDI tab includes plugin parameter mapping (3-step popup: plugin → parameter → Learn). / 3개 서브탭: 단축키, MIDI, Stream Deck. 각 탭은 별도 클래스: HotkeyTab, MidiTab, StreamDeckTab. MIDI 탭에 플러그인 파라미터 매핑 (3단계 팝업).
  • PresetSlotBar — Preset slot A-E button bar, extracted from MainComponent. Handles slot switching, naming (right-click → Rename/Copy/Delete/Export/Import), visual active/occupied state, loading feedback. / MainComponent에서 추출된 프리셋 슬롯 A-E 버튼 바. 슬롯 전환, 이름 지정, 시각적 상태 표시.
  • StatusUpdater — Status bar update logic, extracted from MainComponent. Updates latency, CPU, format, portable mode indicators. Integrates with NotificationBar. / MainComponent에서 추출된 상태 바 업데이트 로직.
  • UpdateChecker — Background GitHub release check + update dialog, extracted from MainComponent. Compares semver, shows "NEW vX.Y.Z" in credit label. Uses alive_ flag (shared_ptr<atomic<bool>>) in callAsync. / MainComponent에서 추출된 백그라운드 업데이트 체크 + 다이얼로그. alive_ 플래그 패턴 사용.
  • SettingsExporter — Two export tiers: (1) Save/Load Settings (.dpbackup) — audio, output, control settings only (no VST chain or slots). (2) Full Backup/Restore (.dpfullbackup) — everything including VST chain + preset slots A-E. Located in Settings tab (LogPanel). Uses controlManager_->getConfigStore() for live config access. Cross-OS protection: Backup files include a platform field (windows/macos/linux). Import checks platform compatibility and blocks cross-OS restore with an alert dialog. Legacy backups without platform field are accepted. / 2단계 내보내기: (1) 설정 저장/불러오기(.dpbackup) — 오디오, 출력, 컨트롤 설정만. (2) 전체 백업/복원(.dpfullbackup) — VST 체인 + 프리셋 슬롯 포함 전체. 크로스 OS 보호: 백업 파일에 platform 필드 포함. 다른 OS에서 복원 시 차단. 플랫폼 필드 없는 레거시 백업은 허용.
  • LevelMeter — Real-time RMS level display with peak hold, clipping indicator. dB log scale. / 실시간 RMS 레벨 미터. 피크 홀드. dB 로그 스케일.
  • LogPanel — 4th tab "Settings" in right panel. Four sections: (1) Application: Auto-start toggle (platform-adaptive label: "Start with Windows" / "Start at Login" (macOS) / "Start on Login" (Linux); Windows: HKCU registry, macOS: LaunchAgent, Linux: XDG autostart) + red "Quit" button (closes individual instance, helps distinguish multiple portables). (2) Settings: Save/Load Settings buttons (.dpbackup via SettingsExporter, settings only). (3) Log: real-time log viewer with timestamped monospaced entries, Export Log / Clear Log buttons. Batch flush optimization: drains all pending lines, single TextEditor insert, single trim pass. (4) Maintenance: Full Backup/Restore (.dpfullbackup), Clear Plugin Cache, Clear All Presets (deletes slots + backups + temps, clears active chain), Factory Reset (deletes ALL data). All with confirmation dialogs. / 우측 패널 4번째 탭 "Settings". 4개 섹션: (1) 시작 프로그램 등록 + 빨간색 "Quit" 버튼 (개별 인스턴스 종료), (2) 설정 저장/불러오기 (설정만), (3) 실시간 로그 뷰어. (4) 유지보수: 전체 백업/복원, 플러그인 캐시 삭제, 전체 프리셋 삭제, 공장 초기화.
  • NotificationBar — Non-intrusive status bar notifications. Temporarily replaces latency/CPU labels. Color-coded: red (errors), orange (warnings), purple (info). Auto-fades after 3-8 seconds depending on severity. / 비침습적 상태 바 알림. 레이턴시/CPU 레이블 임시 대체. 색상: 빨강(오류), 주황(경고), 보라(정보). 3-8초 자동 페이드.
  • DirectPipeLookAndFeel — Custom dark theme (#1E1E2E bg, #6C63FF purple accent, #4CAF50 green). / 다크 테마.

Main Application (host/Source/MainComponent.cpp) / 메인 앱

~729 lines (refactored from ~1835). Delegates to extracted helper classes. / ~729줄 (기존 ~1835줄에서 리팩토링). 추출된 헬퍼 클래스에 위임.

  • Two-column layout: left (input meter + gain + VST chain + PresetSlotBar), right (tabbed panel: Audio/Output/Controls/Settings + output meter) / 2컬럼 레이아웃, 좌우 대칭 미터
  • PresetSlotBar — Quick Preset Slot buttons A-E with visual active/occupied state. Loading feedback (dimmed buttons). / 퀵 프리셋 슬롯 버튼 (활성/사용중 시각 구분, 로딩 중 피드백)
  • ActionHandler — Centralized action handling (replaces 200+ line switch-case). / 중앙 액션 처리 (기존 200줄+ switch-case 대체)
  • SettingsAutosaver — Auto-save via dirty-flag + 1-second debounce. onSettingsChanged callbacks trigger markSettingsDirty(). / dirty-flag + 1초 디바운스 자동 저장
  • StatusUpdater — Status bar: latency, CPU, format, portable mode, "Created by LiveTrack". NotificationBar temporarily replaces status labels with color-coded error/warning/info messages (auto-fade 3-8s). / 상태 바. NotificationBar가 상태 레이블을 색상 코드 오류/경고/정보 메시지로 임시 대체 (3-8초 자동 페이드).
  • UpdateChecker — Shows "NEW vX.Y.Z" in orange when newer GitHub release exists (background update check on startup, uses alive_ flag to guard callAsync UI update). / 새 릴리즈 시 주황색 "NEW" 표시 (백그라운드 업데이트 체크, alive_ 플래그 패턴).
  • Panic mute remembers pre-mute state (monitor, output mute, IPC), restores on unmute. Active recording is stopped on panic engage (does not auto-restart). During panic mute, OUT/MON/VST buttons are locked and most external-control actions are blocked; InputMuteToggle/XRunReset/SafetyLimiter controls/AutoProcessorsAdd remain available by design. / Panic Mute: pre-mute 상태(모니터, 출력, IPC) 기억/복원. 패닉 시 녹음 자동 중지 (해제 시 재시작 안 함). 패닉 중 OUT/MON/VST 버튼은 잠기고 대부분 액션이 차단되며, InputMuteToggle/XRunReset/리미터 제어/AutoProcessorsAdd는 설계상 허용.
  • System tray tooltip: shows current state (preset, plugins, volumes). Atomic dirty-flag for cross-thread safety. / 시스템 트레이 툴팁: 현재 상태 표시. atomic dirty-flag로 스레드 안전.

System Tray (host/Source/Main.cpp)

  • Process priority set to HIGH_PRIORITY_CLASS at startup (Windows). timeBeginPeriod(1) for 1ms timer resolution (Windows). Power Throttling disabled for Intel hybrid CPUs (Windows). macOS/Linux: standard JUCE process defaults. / 시작 시 프로세스 우선순위 HIGH (Windows). 1ms 타이머 해상도 (Windows). Intel 하이브리드 CPU Power Throttling 비활성화 (Windows). macOS/Linux: JUCE 기본값.
  • Close button -> minimize to tray / X 버튼 -> 트레이 최소화
  • Double-click or left-click tray icon -> show window / 트레이 아이콘 클릭 -> 창 복원
  • Right-click -> popup menu: "Show Window", auto-start toggle (Windows: "Start with Windows", macOS: "Start at Login", Linux: "Start on Login"), "Quit DirectPipe" / 우클릭 -> 메뉴 (자동 시작 라벨은 플랫폼별 표시)
  • Auto-start: Windows via HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run, macOS via LaunchAgent (~/Library/LaunchAgents/), Linux via XDG autostart (~/.config/autostart/) / 자동 시작: Windows 레지스트리, macOS LaunchAgent, Linux XDG autostart
  • Out-of-process scanner mode via --scan argument / --scan 인자로 스캐너 모드
  • Multi-instance external control priority — Named Mutexes coordinate which instance owns hotkeys/MIDI/WebSocket/HTTP. Windows: CreateMutex (DirectPipe_NormalRunning, DirectPipe_ExternalControl), TOCTOU-safe (ERROR_ALREADY_EXISTS, no OpenMutex probe for normal mode). macOS/Linux: POSIX file locks (/tmp/). acquireExternalControlPriority() returns: 1 (full control), 0 (audio only), -1 (blocked/quit). Normal mode blocks if portable has control. Portable runs audio-only if normal is running or another portable already has control. Audio-only mode skips HotkeyHandler, MidiHandler, WebSocketServer, HttpApiServer, UDP discovery. UI: title bar "(Audio Only)", status bar orange "Portable", tray tooltip "(Portable/Audio Only)". / 다중 인스턴스 외부 제어 우선순위 — Windows: Named Mutex, macOS/Linux: POSIX 파일 잠금으로 단축키/MIDI/WS/HTTP 소유권 조정. acquireExternalControlPriority() 반환값: 1(전체 제어), 0(오디오만), -1(차단/종료). 일반 모드는 포터블이 제어 중이면 차단. 포터블은 일반이 실행 중이거나 다른 포터블이 제어 중이면 오디오만. Audio-only 모드는 외부 제어 스킵. UI: 타이틀 바 "(Audio Only)", 상태 바 주황색 "Portable", 트레이 "(Portable/Audio Only)".
  • Portable modeportable.flag file next to exe → config stored in ./config/ instead of %AppData%/DirectPipe/. Enables multi-instance from different folders. / 포터블 모드 — exe 옆 portable.flag%AppData% 대신 ./config/에 설정 저장. 다른 폴더에서 다중 인스턴스 가능.

2. Core Library (core/) / 코어 라이브러리

Shared static library for IPC. No JUCE dependency. / IPC용 정적 라이브러리. JUCE 의존성 없음.

  • RingBuffer — SPSC lock-free ring buffer. std::atomic with acquire/release. Cache-line aligned (alignas(64)). Power-of-2 capacity. Atomic detached_ flag for safe teardown (blocks read/write immediately on detach). / SPSC 락프리 링 버퍼. atomic detached_ 플래그로 안전한 해제 (detach 시 읽기/쓰기 즉시 차단).
  • SharedMemory — Shared memory wrapper. Windows: CreateFileMapping/MapViewOfFile with named events. macOS/Linux: POSIX shm_open/mmap with named semaphores (permissions 0600, owner-only). / 공유 메모리 래퍼. Windows: CreateFileMapping/MapViewOfFile. macOS/Linux: POSIX shm_open/mmap (퍼미션 0600, 소유자 전용).
  • Protocol — Shared header structure for IPC communication. / IPC 헤더 구조체.
  • Constants — Buffer names, sizes, sample rates. / 상수.

3. DirectPipe Receiver Plugin (VST2/VST3/AU) (plugins/receiver/) / DirectPipe Receiver 플러그인 (VST2/VST3/AU)

Plugin for OBS and other hosts. Reads processed audio from DirectPipe via shared memory IPC (core library). Output-only plugin (no input bus) — host audio upstream of the plugin is completely replaced by IPC data. Supports mono and stereo output layouts (isBusesLayoutSupported override). Reports buffering latency to the host DAW via setLatencySamples(targetFillFrames). Available as VST2, VST3, and AU (macOS). OBS only supports VST2 on all platforms. / OBS 등에서 사용하는 플러그인. 공유 메모리 IPC(core 라이브러리)를 통해 DirectPipe의 처리된 오디오를 읽음. 입력 버스가 없는 출력 전용 플러그인 — 호스트에서 플러그인 앞단의 오디오는 IPC 데이터로 완전히 대체됨. 모노 및 스테레오 출력 레이아웃 지원 (isBusesLayoutSupported 오버라이드). setLatencySamples(targetFillFrames)를 통해 버퍼링 레이턴시를 호스트 DAW에 보고. VST2, VST3, AU(macOS) 포맷 제공. OBS는 모든 플랫폼에서 VST2만 지원.

  • Consumes shared memory IPC written by SharedMemWriter / SharedMemWriter가 기록한 공유 메모리 IPC를 소비
  • SPSC (Single Producer Single Consumer) ring buffer — only one Receiver instance can read at a time. A second Receiver attaching will see a consumer_active warning in the UI (audio will be corrupted due to readPos_ double-advance). / SPSC 링 버퍼 — Receiver는 한 번에 하나만 읽기 가능. 두 번째 Receiver 연결 시 consumer_active 경고 표시 (readPos_ 이중 전진으로 오디오 깨짐).
  • Configurable buffer size (5 presets): Ultra Low (~5ms), Low (~10ms), Medium (~21ms), High (~42ms), Safe (~85ms) / 버퍼 크기 설정 가능 (5단계 프리셋)
  • Bidirectional clock drift compensation / 양방향 클록 드리프트 보상:
    • Warmup: first 50 blocks after connect are skipped (drift checks inactive) / 워밍업: 연결 후 50블록은 드리프트 체크 비활성
    • High-fill (producer faster than consumer): when buffer fill > highThreshold, excess frames are discarded until fill returns to targetFill. Prevents buffer overflow and growing latency. / 프로듀서가 빠를 때: 버퍼가 highThreshold 초과 시 targetFill까지 초과분 폐기. 지연 증가 방지.
    • Low-fill (consumer faster than producer): when buffer fill < lowThreshold / 2, read amount is halved (numSamples / 2). Remaining output samples are zero-padded, creating micro-gaps instead of hard clicks. A hysteresis dead-band between lowThreshold/2 and lowThreshold prevents oscillation between throttle and normal mode. / 컨슈머가 빠를 때: 버퍼가 lowThreshold/2 미만이면 읽기량 절반. 나머지는 무음 패딩 (마이크로 갭). lowThreshold/2와 lowThreshold 사이에 히스테리시스 데드 밴드가 있어 스로틀/정상 모드 간 진동을 방지.
    • Buffer presets define {targetFill, highThreshold, lowThreshold} per preset level / 버퍼 프리셋별 {targetFill, highThreshold, lowThreshold} 정의
    • Long-term stability: drift correction runs continuously after warmup. No resampling — adjustments are purely read-rate throttling/skipping. Suitable for indefinite streaming sessions. / 장시간 안정성: 워밍업 후 지속적 보정. 리샘플링 없이 읽기 속도 조절/스킵 방식. 무기한 스트리밍 세션에 적합.
  • IPC output can be toggled on/off via IpcToggle action / IPC 출력은 IpcToggle 액션으로 켜기/끄기 가능

4. Stream Deck Plugin (com.directpipe.directpipe.sdPlugin/) / 스트림 덱 플러그인

Elgato Stream Deck plugin (Node.js, @elgato/streamdeck SDKVersion 3). / Stream Deck 플러그인 (SDKVersion 3).

  • Connects via WebSocket (ws://localhost:8765) / WebSocket으로 연결
  • 10 SingletonAction subclasses: Bypass Toggle, Panic Mute, Volume Control, Preset Switch, Monitor Toggle, Recording Toggle, IPC Toggle, Performance Monitor, Plugin Parameter (SD+), Preset Bar (SD+) / 10개 액션
  • Volume Control supports 3 modes: Mute Toggle, Volume Up (+), Volume Down (-) with configurable step size / 볼륨 제어: 뮤트 토글, 볼륨 +/- 모드
  • SD+ dial support: Volume Control (dial adjust), Plugin Parameter (dial adjust) / SD+ 다이얼: 볼륨 제어, 플러그인 파라미터 조절
  • SD+ touchscreen: Preset Bar (touch layout) / SD+ 터치스크린: Preset Bar
  • Event-driven reconnection: UDP discovery (port 8767) + user-action trigger (no polling) / 이벤트 기반 재연결: UDP 디스커버리 + 사용자 조작 트리거 (폴링 없음)
  • Pending message queue (cap 50) while disconnected / 연결 해제 중 대기 큐 (최대 50)
  • Property Inspector HTML (sdpi-components v4) for each action / 각 액션별 설정 UI
  • SVG icon sources in icons-src/, PNG generation via scripts/generate-icons.mjs / SVG 원본 + PNG 생성 스크립트
  • Packaged as .streamDeckPlugin in dist/ / dist/에 패키징

Data Flow (Audio Thread) / 데이터 흐름 (오디오 스레드)

1. Audio driver callback fires (WASAPI/ASIO on Win, CoreAudio on macOS, ALSA/JACK on Linux). ScopedNoDenormals set. / 오디오 드라이버 콜백 발생 (Win: WASAPI/ASIO, macOS: CoreAudio, Linux: ALSA/JACK). ScopedNoDenormals 설정.
2. If muted: zero output, reset levels, return early (fast path) / 뮤트 시: 출력 0, 레벨 리셋, 즉시 반환 (고속 경로)
3. Input PCM float32 copied to pre-allocated work buffer (no heap alloc) / 입력 PCM float32를 사전 할당된 버퍼에 복사 (힙 할당 없음)
4. Channel processing: Mono (average L+R) or Stereo (passthrough) / 채널 처리: Mono (좌우 평균) 또는 Stereo (패스스루)
5. Apply input gain (atomic float) / 입력 게인 적용 (atomic float)
6. Measure input RMS level (every 4th callback — decimation) / 입력 RMS 레벨 측정 (4번째 콜백마다 — 데시메이션)
7. Process through VST chain (graph->processBlock, inline, pre-allocated MidiBuffer) / VST 체인 처리 (인라인, 사전 할당된 MidiBuffer)
8. Safety Limiter (brickwall-style with look-ahead + hard clamp, in-place on workBuffer — before ALL output paths) / Safety Limiter (look-ahead + 하드 클램프 기반 브릭월 스타일, workBuffer 인플레이스 — 모든 출력 경로 전에 적용)
9. Write to AudioRecorder (if recording, lock-free) / AudioRecorder에 기록 (녹음 중이면, 락프리)
10. Write to SharedMemWriter (if IPC enabled) / SharedMemWriter에 기록 (IPC 활성화 시)
11. OutputRouter routes to monitor (if enabled) / OutputRouter가 모니터로 라우팅 (활성화 시):
    Monitor -> volume scale -> lock-free AudioRingBuffer -> MonitorOutput (separate audio device)
12. Apply output volume + copy to main output (outputChannelData) / 출력 볼륨 적용 + 메인 출력(outputChannelData)에 복사
13. Measure output RMS level (every 4th callback) / 출력 RMS 레벨 측정 (4번째 콜백마다)

Preset System / 프리셋 시스템

Auto-save (settings.dppreset) / 자동 저장

  • Audio settings (driver type, devices, sample rate, buffer size, input gain) / 오디오 설정
  • VST chain (plugins, order, bypass, internal state) / VST 체인
  • Output settings (volumes, enables) / 출력 설정
  • Active slot index / 활성 슬롯
  • Used for app restart restoration only / 앱 재시작 복원용

Settings Save/Load (.dpbackup) / 설정 저장/불러오기

  • Audio/output settings + control mappings (hotkeys, MIDI) / 오디오/출력 설정 + 컨트롤 매핑
  • Does NOT include VST chain or preset slots / VST 체인, 프리셋 슬롯 미포함

Full Backup/Restore (.dpfullbackup) / 전체 백업/복원

  • Everything: audio settings + VST chain + control mappings + all preset slots A-E / 전체 포함
  • Located in Settings tab > Maintenance section / Settings 탭 > Maintenance 섹션
  • Same-OS only: Backup files include platform info; cross-OS restore is blocked (device types, plugin paths, hotkey codes are OS-specific) / 같은 OS끼리만: 백업 파일에 플랫폼 정보 포함; 다른 OS에서 복원 시 차단 (디바이스 타입, 플러그인 경로, 핫키 코드가 OS 종속적)

Quick Preset Slots (A-E) / 퀵 프리셋 슬롯

  • Chain-only: plugins, order, bypass state, plugin internal parameters / 체인 전용
  • Audio/output settings are NOT affected by slot switching / 오디오/출력 설정 영향 없음
  • Same-chain fast path: bypass + state update only (typically near-instant) / 동일 체인: 보통 거의 즉시 전환
  • Different-chain: async background loading with Keep-Old-Until-Ready (old chain processes audio during load, atomic swap when ready — often ~10-50ms in lighter/cache-hit cases, but varies by plugin set and system load). asyncGeneration_ counter discards stale load callbacks. / 다른 체인: 비동기 로딩 + Keep-Old-Until-Ready (로딩 중 이전 체인이 오디오 처리 유지, 완료 시 원자적 스왑. 가벼운 로드나 캐시 히트 상황에서는 흔히 ~10-50ms 수준이지만, 플러그인 구성과 시스템 부하에 따라 달라짐)
  • Auto-save on any change (dirty-flag + 1s debounce), editor close, slot switch. Cache invalidated only on structure change (plugin names/paths/order via isCachedWithStructure), not on parameter-only saves / 변경 시 자동 저장. 구조 변경 시에만 캐시 무효화 (파라미터만 변경 시 유지)

Plugin State Serialization / 플러그인 상태 직렬화

  • PluginDescription saved as XML via createXml() / XML 저장
  • Plugin internal state via getStateInformation() -> base64 / 내부 상태 base64 인코딩
  • Restored via setStateInformation() after plugin load / 로드 후 복원

Thread Safety Rules / 스레드 안전 규칙

  1. Audio callback (RT thread) — No heap allocation, no mutexes, no I/O. Pre-allocated buffers only. / 힙 할당, 뮤텍스, I/O 금지. 사전 할당 버퍼만.
  2. Control -> Audiostd::atomic flags only / atomic 플래그만 사용
  3. Graph modificationsuspendProcessing(true) before, false after / 그래프 수정 시 처리 일시 중지
  4. Chain modificationchainLock_ (mutable CriticalSection) protects ALL chain access (readers AND writers), never held in processBlock. prepared_ is std::atomic<bool>. Never call writeToLog inside chainLock_ — capture log string under lock, log after releasing (prevents lock-ordering hazard with DirectPipeLogger writeMutex_). / chainLock_(mutable CriticalSection)이 모든 체인 접근(리더+라이터) 보호, processBlock에서는 미사용. prepared_std::atomic<bool>. chainLock_ 내부에서 writeToLog 호출 금지 — lock 내에서 로그 문자열을 캡처하고 lock 해제 후 로그 기록 (DirectPipeLogger writeMutex_와의 lock-ordering 위험 방지).
  5. Async chain loading — Plugins loaded on std::thread, wired on message thread / 백그라운드 로드, 메시지 스레드에서 연결
  6. onChainChanged callback — Called OUTSIDE chainLock_ scope (deadlock prevention) / chainLock_ 범위 밖에서 호출
  7. WebSocket/HTTP — Separate threads, communicate via ActionDispatcher (message-thread delivery guaranteed) / 별도 스레드, ActionDispatcher가 메시지 스레드 전달 보장
  8. ActionDispatcher/StateBroadcaster — Both guarantee message-thread delivery. Callers from any thread (MIDI, WebSocket, HTTP, hotkey) are deferred via callAsync; message-thread callers execute synchronously. / 둘 다 메시지 스레드 전달 보장. 외부 스레드 호출은 callAsync로 지연, 메시지 스레드 호출은 동기 실행.
  9. UI component deletion — Use juce::MessageManager::callAsync for safe self-deletion / callAsync로 안전 삭제
  10. Slot auto-save guardloadingSlot_ (atomic) flag prevents recursive saves / 재귀 저장 방지
  11. Dirty-flag auto-savesettingsDirty_ + dirtyCooldown_ debounce (1s). onSettingsChanged callbacks trigger markSettingsDirty() / dirty-flag 디바운스 자동 저장
  12. callAsync lifetime guards — Classes using callAsync from background threads protect against use-after-delete. checkForUpdate (UpdateChecker), VSTChain::replaceChainAsync, ActionDispatcher, StateBroadcaster use shared_ptr<atomic<bool>> alive_ flag pattern (captured by value in lambda, checked before accessing this). / callAsync를 백그라운드 스레드에서 사용하는 클래스는 소멸 후 접근을 방지. checkForUpdate(UpdateChecker), VSTChain::replaceChainAsync, ActionDispatcher, StateBroadcastershared_ptr<atomic<bool>> alive_ 플래그 패턴 (람다에서 값 캡처, this 접근 전 확인).
  13. MidiHandler bindings mutexstd::mutex bindingsMutex_ protects all access to bindings_. getBindings() returns a copy for safe iteration outside the lock. processCC/processNote collect matching actions into a local vector, dispatch OUTSIDE bindingsMutex_ (deadlock prevention). / std::mutex bindingsMutex_bindings_ 접근 전체를 보호. getBindings()는 잠금 밖에서 안전한 반복을 위해 복사본 반환. processCC/processNote는 매칭 액션을 로컬 벡터에 수집 후 bindingsMutex_ 밖에서 디스패치 (교착 방지).
  14. Notification queue overflow guardpushNotification checks ring buffer capacity before write to prevent overflow. Queue indices use uint32_t (overflow-safe). / pushNotification이 오버플로 방지를 위해 쓰기 전 링 버퍼 용량 확인. 큐 인덱스는 uint32_t 사용 (오버플로 안전).
  15. WebSocket broadcast mutex releasebroadcastToClients releases clientsMutex_ before socket writes (reduces global lock contention on slow clients) and joins dead client threads outside lock to prevent deadlock. / broadcastToClients가 소켓 쓰기 전에 clientsMutex_를 해제해 느린 클라이언트에서 전역 락 경합을 줄이고, dead client 스레드 join은 잠금 밖에서 수행해 교착을 방지.
  16. OutputRouter bounds checkrouteAudio() clamps numSamples to scaledBuffer_ capacity to prevent buffer overrun. / routeAudio()numSamplesscaledBuffer_ 용량에 클램프하여 버퍼 오버런 방지.
  17. HTTP proper status codesprocessRequest returns pair<int, string> with correct status codes (404 Not Found, 405 Method Not Allowed, 400 Bad Request) instead of always 200. / processRequest가 올바른 상태 코드(404/405/400)를 pair<int, string>으로 반환.
  18. WebSocket RFC 7230 compliance — Case-insensitive HTTP header matching during handshake. / 핸드셰이크 시 대소문자 무시 HTTP 헤더 매칭.
  19. SafePointer in callAsyncPluginChainEditor::addPluginFromDescription, PluginScanner (all 3 background callAsync lambdas), and Main.cpp tray tooltip (activeSlot 0-5 or -1, no clamping) use SafePointer for lifetime safety. / PluginChainEditor::addPluginFromDescription, PluginScanner(백그라운드 callAsync 3개), Main.cpp 트레이 툴팁(activeSlot 0-5 또는 -1, 클램프 없음)이 수명 안전을 위해 SafePointer 사용.
  20. VSTChain movePlugineditorWindows_ resized to match chain_ size before move to prevent out-of-bounds access. / movePlugin에서 이동 전 editorWindows_chain_ 크기에 맞춰 조정하여 범위 초과 접근 방지.
  21. VSTChain asyncGeneration_uint32_t atomic counter incremented per replaceChainAsync call. Background thread captures generation at start; callAsync callback checks gen == asyncGeneration_ before modifying graph (discards stale callbacks from superseded loads). / replaceChainAsync 호출마다 증가하는 uint32_t atomic 카운터. 백그라운드 스레드가 시작 시 generation 캡처; callAsync 콜백이 그래프 수정 전 gen == asyncGeneration_ 확인 (대체된 로드의 stale 콜백 폐기).
  22. AudioEngine device reconnectiondeviceLost_ atomic set by audioDeviceError, cleared by audioDeviceAboutToStart and by setInputDevice/setOutputDevice (manual device selection during loss). Dual mechanism: ChangeListener (immediate) + 3s timer (fallback). desiredInputDevice_/desiredOutputDevice_ tracked. attemptReconnection() preserves SR/BS/channel routing. attemptingReconnection_ re-entrancy guard (message thread only). reconnectMissCount_ fallback (accept current devices after 5 misses) only applies to cross-driver stale name scenarios; when outputAutoMuted_ is true (genuine device loss), counter resets and waits indefinitely. / deviceLost_ atomic 플래그 — audioDeviceError에서 설정, audioDeviceAboutToStartsetInputDevice/setOutputDevice(손실 중 수동 선택)에서 해제. 듀얼 감지 메커니즘 + 재진입 가드. reconnectMissCount_ 폴백은 교차 드라이버 이름 불일치에만 적용; outputAutoMuted_ true(실제 장치 손실)시 무기한 대기.
  23. MonitorOutput device reconnectionmonitorLost_ atomic set by audioDeviceError/audioDeviceStopped (external events only — shutdown() removes callback first). Cleared ONLY by audioDeviceAboutToStart. Independent 3s cooldown. / 모니터 독립 재연결 + shutdown이 콜백 먼저 제거.
  24. WebSocket sendFrame bool returnsendFrame returns bool; on false, broadcastToClients closes socket for immediate dead client detection (prevents repeated write-error log spam). / sendFramebool 반환; 실패 시 소켓 즉시 닫아 dead client 감지.