디지털 MP3/아날로그 카세트, 파이썬 Librosa로 구현한 음원 스펙트로그램 비교 분석기

안녕하세요, 오키 회원 여러분! 👋 잡학다식 개발자 gohard Lab 입니다.
요즘 레트로 열풍으로 카세트테이프의 따뜻한 아날로그 감성이 다시 주목받고 있죠. 그런데 문득 개발자 특유의 호기심이 발동했습니다. "감성이라는 추상적인 느낌을 파이썬 데이터로 시각화해서 눈으로 직접 비교해 볼 수는 없을까?"
그래서 최신 디지털 MP3 원본과 데크를 통해 카세트테이프로 녹음한 음원의 주파수 대역을 비교 분석하는 오디오 스펙트로그램 대시보드를 만들어 보았습니다. 오늘은 이 프로젝트의 핵심 소스코드와 함께, 주파수 지도가 그려지는 내부 메커니즘을 공유해 드립니다!
💻 핵심 파이썬 처리 로직 (Streamlit + Librosa)
음원 파일을 업로드받아 일반적인 파형과 스펙트로그램(주파수 지도)으로 변환하는 시각화 함수입니다.
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
import tempfile
import os
def plot_audio_data(audio_file, title):
# 1. 원본 확장자를 유지한 임시 파일 생성 (에러 방지 트릭)
file_extension = os.path.splitext(audio_file.name)[1]
with tempfile.NamedTemporaryFile(delete=False, suffix=file_extension) as tmp_file:
tmp_file.write(audio_file.read())
tmp_path = tmp_file.name
try:
# 2. 오디오 데이터 로드
y, sr = librosa.load(tmp_path)
finally:
if os.path.exists(tmp_path):
os.unlink(tmp_path)
# 3. 윈도우 한글 및 마이너스 부호 깨짐 방지 폰트 설정
plt.rcParams['font.family'] = 'Malgun Gothic'
plt.rcParams['axes.unicode_minus'] = False
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), constrained_layout=True)
# 4. 주파수 파형 시각화
librosa.display.waveshow(y, sr=sr, ax=ax1, color="blue")
ax1.set_title(f"{title} - 주파수 파형")
# 5. 무지개색 주파수 지도(스펙트로그램) 시각화
stft_data = librosa.stft(y)
stft_db = librosa.amplitude_to_db(np.abs(stft_data), ref=np.max)
img = librosa.display.specshow(stft_db, sr=sr, x_axis="time", y_axis="log", ax=ax2, cmap="rainbow")
ax2.set_title(f"{title} - 무지개색 주파수 지도")
fig.colorbar(img, ax=ax2, format="%+2.0f dB")
return fig🎨 오디오 주파수 지도가 그려지는 4단계 과정
음원 파일을 넣었을 때 파이썬 내부에서 알록달록한 주파수 지도가 완성이 되기까지는 다음과 같은 4단계 가공 과정을 거치게 됩니다. ⚙️
1️⃣ 🎵 음원 데이터의 수치화 (librosa.load) 컴퓨터는 소리 자체를 직접 이해하지 못합니다. 가장 먼저 음원 파일의 소리 파동을 파이썬이 계산할 수 있는 연속된 거대한 숫자 배열로 디코딩합니다.
2️⃣ ✂️ 시간 단위 분쇄 및 주파수 추출 (librosa.stft) 단시간 푸리에 변환 기술을 사용합니다. 오디오 신호를 아주 짧은 시간 단위로 썰어낸 뒤, 그 찰나의 순간 안에 어떤 높낮이의 소리(주파수)들이 얼마나 섞여 있는지 수학적으로 분리해 냅니다.
3️⃣ 📉 데시벨 단위 압축 (librosa.amplitude_to_db) 컴퓨터가 추출한 소리의 에너지 수치는 편차가 어마어마하게 큽니다. 이 수치들을 사람이 실제로 듣는 감각과 유사한 데시벨(dB) 단위로 압축해 주어야 그래프상에서 잔잔한 소리와 큰 소리가 고루 보입니다.
4️⃣ 🌈 렌더링 및 색상 매핑 (librosa.display.specshow) 데시벨 배열에 색상을 입힙니다. 에너지가 강한 구간은 붉은색, 약한 구간은 푸른색이 나타나도록 무지개색 컬러맵을 매핑하여 시각적인 지도로 완성합니다.
🔬 신호 처리 이론과 실무 개발에서의 현실적 타협점
이론상으로는 푸리에 변환을 쓰면 소리의 시간과 주파수를 모두 완벽하게 분석할 수 있을 것 같지만, 실제 현업 오디오 개발에서는 시간 정밀도와 주파수 정밀도를 동시에 가져갈 수 없는 불확정성 원리가 존재합니다.
시간 정밀도를 높이려고 구간을 너무 잘게 쪼개면 음정(주파수)이 뭉개지고, 반대로 주파수를 칼같이 나누려고 구간을 넓게 잡으면 소리가 정확히 몇 초에 발생했는지 시간 정보가 흐려집니다. 따라서 실무 프로젝트에서는 이 두 가지 사이의 타협점(보통 2048개 샘플 프레임)을 적절히 설정하여 시각화 해상도를 최적화합니다.
💡 실전 개발 활용 꿀팁
💡 웹 프레임워크 오디오 인메모리 에러 우회법 Streamlit이나 Flask 등에서 업로드받은 메모리상의 오디오 파일 객체를 Librosa에 바로 넣으면 디코딩 에러가 발생하곤 합니다. 이때 파이썬 내장 tempfile 모듈로 파일 확장자를 살린 임시 파일 경로를 만들어 전달하면 디펜던시 에러 없이 깨끗하게 처리됩니다.
💡 Matplotlib 마이너스 부호 깨짐 방지 한글 폰트를 세팅할 때 axes.unicode_minus 옵션을 False로 주어야 그래프의 데시벨 마이너스 부호가 네모 박스로 깨지지 않고 정상 출력됩니다.
🔗 소스코드 및 시연 영상 안내
이렇게 만든 분석기에 실제 음원을 집어넣었을 때, 아날로그 테이프 데이터의 고주파수 영역이 오손도손 깎여나가는 진귀한 시각화 결과는 아래 시연 영상을 통해 확인하실 수 있습니다.
전체 오픈소스 코드는 깃허브 저장소에 모두 올려두었으니, 오디오 처리나 파이썬 시각화 대시보드 개발에 관심 있는 분들은 편하게 가져가서 활용해 보세요! 코드 구조나 구현 방식에 대해 궁금한 점이 있다면 언제든 편하게 댓글 남겨주시기 바랍니다.
📌 GitHub 원본 소스코드 저장소: https://github.com/gohard-lab/tape_waveform_analyzer
🎬 실제 프로그램 동작 및 시연 영상: https://youtu.be/AgEgcOTplH0
📺 워드프레스: https://gohard.pe.kr/
📌 블로그: https://gohard.pe.kr/
감사합니다!