在python中同步音频和动画

在python中同步音频和动画,python,matplotlib,audio,pydub,Python,Matplotlib,Audio,Pydub,我已经编写了加载音频文件、计算频谱和设置动画的代码。我似乎没有办法用我正在使用的工具将音频与动画同步 我遇到的障碍是pydub实际上没有告诉我我在音频中的位置(尽管我可以计时),matplotlib也没有给我任何控制我在动画中的位置的能力,也没有给我一个保证的帧速率 是否有一种技术或工具组合让我能够解决这个特定的问题 代码如下: from pydub import AudioSegment from pydub.playback import play import matplotlib.pyp

我已经编写了加载音频文件、计算频谱和设置动画的代码。我似乎没有办法用我正在使用的工具将音频与动画同步

我遇到的障碍是pydub实际上没有告诉我我在音频中的位置(尽管我可以计时),matplotlib也没有给我任何控制我在动画中的位置的能力,也没有给我一个保证的帧速率

是否有一种技术或工具组合让我能够解决这个特定的问题

代码如下:

from pydub import AudioSegment
from pydub.playback import play
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy import signal
import numpy as np
import threading
import time
from datetime import timedelta

# Load the audio and get the raw data for transformation
sound = AudioSegment.from_mp3("A Day Without Rain - Enya - Flora's Secret.mp3")
sampling_rate = sound.frame_rate
song_length = sound.duration_seconds
left = sound.split_to_mono()[0]
x = left.get_array_of_samples()

# Fourier transform
f, t, Zxx = signal.stft(x, fs=sampling_rate, nperseg=8820, noverlap=5292)
y = np.abs(Zxx.transpose())

# Setup a separate thread to play the music
music_thread = threading.Thread(target=play, args=(sound,))

# Build the figure
fig = plt.figure(figsize=(14, 6))
plt.style.use('seaborn-bright')
ax = plt.axes(xlim=[0, 4000], ylim=[0, 3000])
line1, = ax.plot([], [])


# Matplotlib function to initialize animation
def init():
    global annotation1, annotation2
    line1.set_data([], [])
    annotation1 = plt.annotate("Music: {}".format(""), xy=(0.2, 0.8), xycoords='figure fraction')
    annotation2 = plt.annotate("Animation: {}".format(""), xy=(0.6, 0.8), xycoords='figure fraction')
    return line1,


# Function for the animation
def animate(i):
    global music_start, annotation1, annotation2
    line1.set_data(f, y[i])
    if i == 0:
        music_thread.start()
        music_start = time.perf_counter()
    annotation1.set_text("Music: {}".format(timedelta(seconds=(time.perf_counter() - music_start))))
    annotation2.set_text("Animation: {}".format(timedelta(seconds=i / t.size * song_length)))
    return line1,


anim = FuncAnimation(fig, animate, init_func=init, interval=55)
plt.show()

嗯,我确实找到了解决问题的方法

事实证明,在设置线数据之前,只需在动画功能中修改帧索引是最简单的:

i = round((time.perf_counter() - music_start)/song_length * t.size)
是的,罗伯·希尔顿

非常感谢您发布此问题和答案!对于其他可能偶然发现这一点并想知道应该将Rob的解决方案放入其原始代码中的人,以下是我如何使其工作的。请注意,
line1.set_data(f,y[i])
需要移动到
if
语句的下方,因为
time.perf_counter()
只对自身的另一个实例起作用

def animate(i):

global music_start, annotation1, annotation2

if i == 0:
    music_thread.start()
    music_start = time.perf_counter()
    
i = round((time.perf_counter() - music_start)/song_length * t.size)
line1.set_data(f, y[i])

annotation1.set_text("Music: {}".format(timedelta(seconds=(time.perf_counter() - music_start))))
annotation2.set_text("Animation: {}".format(timedelta(seconds=i / t.size * song_length)))
return line1,

请删除背景并直接提及问题。我已经删除了一些无关的文本,但是如果我以后必须提供与问题答案相同的上下文,那么没有上下文的问题将不会有帮助。好主意!