Audacity 실시간 음성 변환 플러그인 구현: RealtimeSTT 활용 완벽 가이드

서론: 오디오 편집의 새로운 접근법

오디오 편집 작업에서 음성 내용을 수동으로标记하는 것은 매우 번거로운 과정입니다. 기존 음성 인식 도구는 별도의 파일 내보내기가 필요하거나 응답 속도가 느려 실용성이 낮았습니다. 본 가이드에서는 RealtimeSTT 라이브러리를 활용하여 Audacity용 실시간 음성 변환 플러그인을 구축하는 방법을 설명합니다.

구현 목표

  • 녹음과 동시에 실시간 텍스트 변환
  • 음성 활동 감지를 통한 자동标记
  • 최소 지연 시간의 실시간 피드백

기술 배경: RealtimeSTT 선택 이유

RealtimeSTT는 실시간 음성 인식을 위해 최적화된 라이브러리로 다음 특성을 보유합니다:
항목RealtimeSTT기존 방식
응답 지연200ms 이하2초 이상
메모리 사용500MB 미만 (tiny 모델)1GB 이상
음성 감지Silero/WebRTC 내장별도 통합 필요
오프라인완전 로컬 실행클라우드 의존

개발 환경 구축

필수 조건

  • Audacity 3.3.0 이상 (Nyquist 플러그인 SDK 지원)
  • Python 3.8 이상 (3.10 권장)
  • Git 클라이언트

프로젝트 설정

# 프로젝트 클론
git clone https://github.com/fffdfdfdf/RealtimeSTT
cd RealtimeSTT

# 가상 환경 생성
python -m venv stt-env
source stt-env/bin/activate  # Linux/Mac
# stt-env\Scripts\activate  # Windows

# 의존성 설치
pip install -r requirements.txt
pip install pyaudio wxPython

오디오 흐름 아키텍처

Audacity의 오디오 출력은 외부에서 직접 접근할 수 없습니다. 가상 오디오 케이블을 통해 라우팅하는 방식이 권장됩니다:
  1. VB-Cable (Windows) 또는 PulseAudio Loopback (Linux) 설치
  2. Audacity 출력 디바이스를 가상 케이블로 설정
  3. RealtimeSTT가 가상 케이블 입력 채널을监听

플러그인 핵심 구현

기본 프레임워크 구성

import wx
import numpy as np
from RealtimeSTT import AudioToTextRecorder
import audacity_scripting as aud

class STTPlugin(wx.Frame):
    def __init__(self, parent, title):
        super().__init__(parent, title=title, size=(450, 350))
        
        self.InitUI()
        self.speech_recorder = None
        self.is_active = False
        self.audio_queue = []
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)
    
    def InitUI(self):
        """플러그인 컨트롤 패널 초기화"""
        container = wx.Panel(self)
        layout = wx.BoxSizer(wx.VERTICAL)
        
        # 상태 표시 영역
        self.status_text = wx.StaticText(container, label="상태: 대기 중")
        layout.Add(self.status_text, flag=wx.EXPAND|wx.ALL, border=12)
        
        # 컨트롤 버튼 영역
        button_layout = wx.BoxSizer(wx.HORIZONTAL)
        self.start_btn = wx.Button(container, label="변환 시작")
        self.stop_btn = wx.Button(container, label="변환 중지")
        self.stop_btn.Disable()
        
        button_layout.Add(self.start_btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
        button_layout.Add(self.stop_btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
        
        layout.Add(button_layout, flag=wx.EXPAND|wx.ALL, border=10)
        
        # 결과 표시 영역
        self.output_area = wx.TextCtrl(container, style=wx.TE_MULTILINE|wx.TE_READONLY)
        layout.Add(self.output_area, proportion=1, flag=wx.EXPAND|wx.ALL, border=10)
        
        container.SetSizer(layout)
        self.Layout()
        
        # 이벤트 연결
        self.start_btn.Bind(wx.EVT_BUTTON, self.StartRecognition)
        self.stop_btn.Bind(wx.EVT_BUTTON, self.StopRecognition)

음성 인식 핵심 로직

def StartRecognition(self, event):
    """음성 인식 서비스 시작"""
    self.status_text.SetLabel("상태: 인식 중...")
    self.start_btn.Disable()
    self.stop_btn.Enable()
    
    # AudioToTextRecorder 초기화
    self.speech_recorder = AudioToTextRecorder(
        model="base",
        language="ko",
        enable_realtime_transcription=True,
        realtime_processing_pause=0.1,
        realtime_model_type="tiny",
        on_realtime_transcription_stabilized=self.ProcessTranscription,
        silero_sensitivity=0.3,
        post_speech_silence_duration=0.5
    )
    
    self.speech_recorder.start()

def StopRecognition(self, event):
    """음성 인식 서비스 중지"""
    if self.speech_recorder:
        self.speech_recorder.stop()
        self.speech_recorder.shutdown()
    
    self.status_text.SetLabel("상태: 중지됨")
    self.start_btn.Enable()
    self.stop_btn.Disable()

def ProcessTranscription(self, text):
    """인식 결과 처리"""
    current = self.output_area.GetValue()
    new_text = f"{current}\n{text}" if current else text
    self.output_area.SetValue(new_text)
    
    self.InsertLabel(text)

def InsertLabel(self, text):
    """Audacity에 텍스트 레이블 삽입"""
    time_position = aud.GetInfo("Project", "SelectionStart")
    
    aud.AddLabel(
        position=time_position,
        text=text,
        label_track="STT_results"
    )

외부 오디오 주입 구현

def FeedAudioStream(self, audio_buffer, sample_rate):
    """Audacity에서 오디오 데이터 주입"""
    # 형식 변환: 32비트 부동소수 → 16비트 정수
    normalized_audio = (audio_buffer * 32767).astype(np.int16)
    
    # 오디오 데이터 푸시
    self.speech_recorder.feed_audio(
        chunk=normalized_audio.tobytes(),
        original_sample_rate=sample_rate
    )

음성 활동 감지 (VAD) 구현

감도 설정 최적화

# 조용한 환경용 Silero VAD 설정
silero_sensitivity=0.2,
silero_deactivity_detection=True,

# 소음이 많은 환경용 WebRTC VAD 설정  
webrtc_sensitivity=3,
post_speech_silence_duration=0.6

자동 세그멘테이션

def __init__(self, parent, title):
    super().__init__(parent, title=title)
    self.voice_start_marker = None
    
def OnVoiceStart(self):
    """음성 세그먼트 시작 이벤트"""
    self.voice_start_marker = aud.GetInfo("Project", "SelectionStart")
    print(f"음성 시작 시점: {self.voice_start_marker}s")

def OnVoiceEnd(self):
    """음성 세그먼트 종료 이벤트"""
    if self.voice_start_marker:
        end_time = aud.GetInfo("Project", "SelectionStart")
        segment_duration = end_time - self.voice_start_marker
        
        # 1초 이상 세그먼트에 대해 레이블 생성
        if segment_duration > 1.0:
            aud.AddLabel(
                position=self.voice_start_marker,
                text=f"음성 구간 ({segment_duration:.1f}초)",
                label_track="자동 세그먼트"
            )
        
        self.voice_start_marker = None

플러그인 배포

플러그인 정의 파일 생성

{
    "name": "STT_Plugin",
    "id": "audio.stt.realtime",
    "version": "1.0",
    "description": "실시간 음성 변환 및 자동 레이블링",
    "category": "Analysis",
    "type": "effect",
    "executable": "python3 -m stt_audacity_plugin"
}

설치 경로

  • Windows: C:\Users\<사용자>\AppData\Roaming\Audacity\Plug-Ins
  • Mac: ~/Library/Application Support/audacity/Plug-Ins
  • Linux: ~/.audacity-data/Plug-Ins

성능 최적화 전략

모델 선택 가이드

하드웨어권장 모델메모리지연시간
저사양 노트북tiny~300MB<100ms
중급 PCbase~500MB100-200ms
고성능 PCsmall~1GB200-300ms

최적화 파라미터

# CPU 부하 감소 설정
realtime_batch_size=32,
allowed_latency_limit=200,

# 메모리 절약 설정
use_main_model_for_realtime=True,
compute_type="int8"

문제 해결 가이드

문제 1: Audacity 오디오 감지 실패

# Linux: PulseAudio 루프백 디바이스 확인
pactl list sources | grep -i "loopback"
오디오 출력과 입력 모두 가상 케이블로 설정되어 있는지 확인합니다.

문제 2: 인식 지연过高

  • tiny 모델로 전환
  • realtime_processing_pause를 0.2로 증가
  • faster_whisper_vad_filter 비활성화

문제 3: 한국어 인식 정확도 낮음

AudioToTextRecorder(
    model="medium",
    language="ko",
    initial_prompt="다음은 한국어 음성입니다"
)

마무리

RealtimeSTT와 Audacity의 통합을 통해 음성 인식과 오디오 편집을 원활하게 연결할 수 있습니다. 이 플러그인은 실시간 변환과 음성 활동 감지를 결합하여 편집 효율성을 크게 향상시킵니다. 향후拓展 가능 방향:
  • 다국어 혼합 인식
  • 의미 기반 스마트 세그멘테이션
  • 자막 파일 직접 생성
  • 전문 용어詞典 활용

태그: python audacity realtimestt speech-recognition plugin-development

6월 12일 22:02에 게시됨