서론: 오디오 편집의 새로운 접근법
오디오 편집 작업에서 음성 내용을 수동으로标记하는 것은 매우 번거로운 과정입니다. 기존 음성 인식 도구는 별도의 파일 내보내기가 필요하거나 응답 속도가 느려 실용성이 낮았습니다. 본 가이드에서는 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의 오디오 출력은 외부에서 직접 접근할 수 없습니다. 가상 오디오 케이블을 통해 라우팅하는 방식이 권장됩니다:
- VB-Cable (Windows) 또는 PulseAudio Loopback (Linux) 설치
- Audacity 출력 디바이스를 가상 케이블로 설정
- 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 |
| 중급 PC | base | ~500MB | 100-200ms |
| 고성능 PC | small | ~1GB | 200-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의 통합을 통해 음성 인식과 오디오 편집을 원활하게 연결할 수 있습니다. 이 플러그인은 실시간 변환과 음성 활동 감지를 결합하여 편집 효율성을 크게 향상시킵니다.
향후拓展 가능 방향:
- 다국어 혼합 인식
- 의미 기반 스마트 세그멘테이션
- 자막 파일 직접 생성
- 전문 용어詞典 활용