본문 바로가기

프로젝트 정리

국비 데이터 분석 3차 _ 음원 분석 이해 및 전처리

음원을 분석하려면 음악을 숫자로 입력받은 wav파일 형식이어야 했다.

 

wav파일은 데이터를 숫자로 기록하는데 오디오 샘플의 순간(1/samplerate 초)을 좌우폭, 음역대의 2차원 공간에 이를 시간으로 길게 이어준 데이터이다.

 

이 데이터(signal)을 뽑아내 분석해야했다.

import numpy
import scipy.io.wavfile
from scipy.fftpack import dct
import numpy as np
import matplotlib.pyplot as plt
file_path = "heize_bingle.wav"
sample_rate, signal = scipy.io.wavfile.read(file_path)  # wav 파일 가져오기
signal = signal[int(0 * sample_rate):int(180 * sample_rate)]  # 30초만 가져오기

이렇게 뽑아낸 데이터를 보면 왼쪽과 오른쪽의 두개의 시계열 진동이 나타난다.

# 시간 설정
[i/sample_rate for i, _ in enumerate(signal)]

def x_to_time(signal, sample_rate):
    return [i/sample_rate for i, _ in enumerate(signal)]
    
plt.plot(x_to_time(signal, sample_rate), signal)
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.show()

시중에 나오는 음원은 마스터링 과정에서 맥시마이저로 음압을 가득차게 해준다. 이러면 분석할 때 signal의 특징이 일정해지기 때문에, 일관성을 풀어줘야한다. 그렇기에 여기에 pre-emphasais-filter를 넣어서 신호의 특징을 구별했다. pre-emphasis-filte는 음원 데이터를 저주파의 진동폭을 줄이고, 고주파는 진동폭을 강조해서 평균 스펙트럼 모양을 보상한다.

# 맥시마이저 되어있는 소리를 pre-emphasis filter 로 풀어주기
pre_emphasis = 0.97 # 또는 0.95 0.9357
emphasized_signal = numpy.append(signal[0], signal[1:] - pre_emphasis * signal[:-1])

plt.plot(x_to_time(emphasized_signal, sample_rate),emphasized_signal)
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.show()


음원을 분석하려면 MFCC 등의 특징 벡터로 바꿔야한다.

이 특징벡터는 음원 신호의 주파수는 시간에 따라 변화하는데 이에 주파수 윤곽이 손실된다. 신호 전체에 걸쳐서 푸리에 변환을 할 경우 의미가 없기에 신호 내의 주파수가 매우 짧은 순간 정지했다는 가정이 필요하다. 즉, 짧은 시간 푸리에 변환 한 프레임을 쭉 연결해서, 주파수 고선의 근사치를 구해야한다.

이 과정을 framing 과정이라고 하는데,  아래 방법을 사용한다.

frame_size = 0.025 # 프레임 사이즈 0.02 ~ 0.04 , 50% (+/-10%) overlap between consecutive frames (0.025 일 때 앞 뒤 프레임이 겹쳐지는 구간이 50% 전후로 나옴)
frame_stride = 0.01 # 0.015보다 작은 값, 10 ms stride (15 ms overlap) 얼마나 떨어져서 볼지 보는 값
# S : 각 진동수 0Hz~44100Hz 까지 0,1로 표현, S * frame 의 순간 구간
frame_length, frame_step = frame_size * sample_rate, frame_stride * sample_rate  

# wav 파일은 float 지원 X, int로 바꾸기
signal_length = len(emphasized_signal)
frame_length = int(round(frame_length))
frame_step = int(round(frame_step))

# ceil은 올림, 프레임이 하나 이상 있어야함
num_frames = int(numpy.ceil(float(numpy.abs(signal_length - frame_length)) / frame_step))  # Make sure that we have at least 1 frame


pad_signal_length = num_frames * frame_step + frame_length

# numpy 초기화
z = numpy.zeros((pad_signal_length - signal_length))

# 원본 신호에서 모든 프레임이 동일한 샘플 수 를 가질 수 있도록 패딩 추가
pad_signal = numpy.append(emphasized_signal, z) 

indices = numpy.tile(numpy.arange(0, frame_length), (num_frames, 1)) + numpy.tile(numpy.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T
frames = pad_signal[indices.astype(numpy.int32, copy=False)]

 


※ mp3 -> wav로 변환이 안 될 경우 ffmpeg 최신 버전을 받아 c:/ 경로에 넣고 환경변수를 지정 후 컴퓨터를 재시작하면 된다. 

https://digital-play.tistory.com/104

 

그리고 변환한 오디오를 다시 묶으려면

리스트 안에 담아 np.array()로 바꿔주면 된다.

 

참고로 파이썬에서 음원을 들으려면 Ipython.display를 이용하면 된다.

from IPython.display import Audio
path2 = 'test.wav'
Audio(path2)