本文将演示如何使用Python创建音乐可视化器。




python改变音频采样率 python 声音频率_python改变音频采样率


如何可视化音乐?

我们首先需要知道音乐是如何组成的,以及如何将它可视化。音乐是声音的组合。声音是我们耳朵检测到的振动。振动由频率和振幅(速度和响度)定义。

最简单的可视化方法是画一排条形图。每个条代表一个频率。当音乐播放时,这些条会根据频率的振幅上下移动。

用Python实现

在开始编码之前,需要安装必须的Python库。本文使用Pygame(图形)和Librosa(声音)。

Librosa具有非常有用的功能,可以帮助我们分析声音。

下面的Python代码返回一个与特定时间相对应的频率幅度的二维数组:

import librosaimport numpy as npimport pygamefilename = "music3.wav"# getting information from the filetime_series, sample_rate = librosa.load(filename)  # getting a matrix which contains amplitude values according to frequency and time indexesstft = np.abs(librosa.stft(time_series, hop_length=512, n_fft=2048*4))# converting the matrix to decibel matrixspectrogram = librosa.amplitude_to_db(stft, ref=np.max)

librosa.load()读取给定文件,并保留有关该文件的信息以供以后使用。mple_rate是每个周期采集的样本数。time_series是一个一维数组,表示每次采样的时间。

Libros.stft()返回包含频率和时间的二维数组。你可以看到我把这个数组从振幅转换成了分贝。除非您使用分贝单位,否则无需执行此步骤。

短时傅里叶变换(STFT)是一种与傅里叶变换相关的变换,用于确定信号局部区域的正弦频率和相位内容,因为它随着时间的变化而变化。

hop_length是帧之间的采样数。n_fft是每一帧的采样数。当增加n_fft时,结果变得更加准确,我将其设置为其默认值的4倍。

您还可以使用matplotlib查看STFT的结果:

librosa.display.specshow(self.spectrogram,                         y_axis='log', x_axis='time')plt.title('Your title')plt.colorbar(format='%+2.0f dB')plt.tight_layout()plt.show()


python改变音频采样率 python 声音频率_python可视化界面设计器_02


您可以使用索引访问数组的值。但是我们该如何选择它的时间和频率呢?

# getting an array of frequenciesfrequencies = librosa.core.fft_frequencies(n_fft=2048*4)  # getting an array of time periodictimes = librosa.core.frames_to_time(np.arange(spectrogram.shape[1]), sr=sample_rate, hop_length=512, n_fft=2048*4)time_index_ratio = len(times)/times[len(times) - 1]frequencies_index_ratio = len(frequencies)/frequencies[len(frequencies)-1]

我将2d数组分成多个数组,这些数组表示特定索引的时间或频率。采样率是常数。因此,我们可以在时间和索引之间创建一个比率,并在频率上创建相同的比率。然后,我们只要把时间和频率乘以这个比率,我们就得到了索引:

def get_decibel(target_time, freq):    return spectrogram[int(freq * frequencies_index_ratio)][int(target_time * time_index_ratio)]

现在,我们需要可视化了。

创建一个代表频率条的类:

def clamp(min_value, max_value, value):    if value < min_value:        return min_value    if value > max_value:        return max_value    return valueclass AudioBar:    def __init__(self, x, y, freq, color, width=50, min_height=10, max_height=100, min_decibel=-80, max_decibel=0):        self.x, self.y, self.freq = x, y, freq        self.color = color        self.width, self.min_height, self.max_height = width, min_height, max_height        self.height = min_height        self.min_decibel, self.max_decibel = min_decibel, max_decibel        self.__decibel_height_ratio = (self.max_height - self.min_height)/(self.max_decibel - self.min_decibel)    def update(self, dt, decibel):        desired_height = decibel * self.__decibel_height_ratio + self.max_height        speed = (desired_height - self.height)/0.1        self.height += speed * dt        self.height = clamp(self.min_height, self.max_height, self.height)    def render(self, screen):        pygame.draw.rect(screen, self.color, (self.x, self.y + self.max_height - self.height, self.width, self.height))

我创建了x、y坐标、条形频率、颜色以及它的高度和分贝的范围。定义高度和分贝之间的比例,以以便稍后确定条形的高度。在update()方法中,我获得了与当前分贝相对应的期望条形图高度,并将速度设置为条形图的增长速度。

pygame.init()infoObject = pygame.display.Info()screen_w = int(infoObject.current_w/2.5)screen_h = int(infoObject.current_w/2.5)# Set up the drawing windowscreen = pygame.display.set_mode([screen_w, screen_h])bars = []frequencies = np.arange(100, 8000, 100)r = len(frequencies)width = screen_w/rx = (screen_w - width*r)/2for c in frequencies:    bars.append(AudioBar(x, 300, c, (255, 0, 0), max_height=400, width=width))    x += width

这里我创建一个数组来保存这些条形图。以100的步长创建了从100Hz到8000Hz的80个条,并将它们添加到数组中。

然后,您只需运行一个Pygame窗口并绘制条形图:

t = pygame.time.get_ticks()getTicksLastFrame = tpygame.mixer.music.load(filename)pygame.mixer.music.play(0)# Run until the user asks to quitrunning = Truewhile running:    t = pygame.time.get_ticks()    deltaTime = (t - getTicksLastFrame) / 1000.0    getTicksLastFrame = t    # Did the user click the window close button?    for event in pygame.event.get():        if event.type == pygame.QUIT:            running = False    # Fill the background with white    screen.fill((255, 255, 255))    for b in bars:        b.update(deltaTime, get_decibel(pygame.mixer.music.get_pos()/1000.0, b.freq))        b.render(screen)    # Flip the display    pygame.display.flip()# Done! Time to quit.pygame.quit()

请注意,这里使用pygame.mixer播放音乐,并使用pygame.mixer.music.get_pos()访问时间。