Math_Music

Posted on 2022-08-15 12:57  罗芭Remoo  阅读(59)  评论(0编辑  收藏  举报

 

查看代码
#REmoo的优化任务
#1、公式写在<formula_set>类中,统一管理              --- Finished 2022.8.15 12:39
#2、建立<sample_set>类,统一管理数据样本             --- Finished 2022.8.15 13:03
#3、统一化manim动画流程                             ---Finished 2022.8.16 11:29
    #1、流程:配置全局参数-导入公式-导入sample-定义坐标图像-
    #2、整理每段Video Clip的animation部分
#4、提高代码重用性


from manim import *
import librosa
import numpy as np
import pickle #写出读取打包 序列化二进制list

# 文件都是以二进制的方式储存在硬盘上
# 那么如果有一个int :13 存在硬盘,转成二进制即可
# 如果我们有一个list [1,2,3,4,5]呢 甚至是 ["hello",12,1.11,Dot()]
# 那么我们就要序列化list 打包好--使用pickle
# 所有文件都是序列化的,方式不同。我用list写出到文件,我就用list的方式读取,中间过程需要序列化。

#import librosa
#import pickle
#samp = [1,2,3,1.11]
#with open('test.iiiiii','rb') as pickle_file:
#    #序列化samp对象,以二进制的方式写到文件
#    pickle.dump(samp,pickle_file)
###################################################
#
#import librosa
#import pickle
#with open('winter.libyy','rb') as pickle_file:
#    #反序列化对象
#    samp_read = pickle.load(pickle_file)
#    print(samp_read)
#>>> samp_read = [1,2,3,1.11]
#

# # ##生成wave文件的数据集样本文件##
# class UsingLibrosa():
#     #利用librosa读取wave文件
#     yy44,fs44 = librosa.load('winter.wav',sr=44100)
#     #写出数据样本文件
#     with open('winter.libyy','wb') as pickle_file:
#         #序列化对象
#         pickle.dump(yy44, pickle_file)

class sys:
    frame_window = 2048

    def Create_Dot_Set(self,axes,sample,Vg,dot_radius=0.02,dot_color=BLUE_A,run_time=1):
        dots_set = []
        _len_sample = int(len(sample))
        for x in range(_len_sample):
            dots_set.append(Dot(radius=dot_radius,color=dot_color,fill_opacity=0.8))
            dots_set[x].move_to(axes.c2p(x,sample[x]))
            self.add(dots_set[x])
            Vg.add(dots_set[x])
        return dots_set


##数据类##
class sample_set:
    def get_winter_wav():
        with open('winter.libyy','rb') as pickle_file:
            #反序列化对象
            sample = pickle.load(pickle_file)
            
            return sample,max(sample)

    def get_sam():
        
        pass

    # WAVE_FILE, SAM_RATE = librosa.load(r'003.wav')
    # NUM_DOTS = len(WAVE_FILE)  # number of discrete point
    # DURATION = NUM_DOTS/SAM_RATE  # duration of the audio (second)
    # SAMPLE_DENSITY = 1 / 1 # the density of point
    # data = WAVE_FILE[1000:1030:int(1/SAMPLE_DENSITY)]
    #len_data = len(data)
    
##公式类##
class formula_set(MathTex):

    formula_001 = MathTex(r"F\left(\omega_{k}\right) \equiv \int_{-\infty}^{\infty} f(t) e^{-2 \pi i k t} \mathrm{~d} t, \quad k \in(-\infty, \infty)")
    formula_002 = [MathTex(
            r"\hat{f}_{k}=\sum_{j=0}^{n-1} f_{j} e^{-i 2 \pi k j / n}"
        ),
            MathTex(
            r"k=0,1,2,...,n-1"
        )  ]

    formula_004 = MathTex(
            r"\left[\begin{array}{l}\
            f_{0} \\\
            f_{1} \\\
            f_{2} \\\
            f_{3} \\\
            f_{4} \\\
            f_{5} \\\
            f_{6} \\\
            f_{7} \\\
            f_{8} \\\
            f_{9} \\\
            \end{array}\right]"
        )


    formula_006 = [
        MathTex(
            r"\left[\begin{array}{l}\
            e^{-i 2 \pi(2(0)) / 9  }\\\
            e^{-i 2 \pi(2(1)) / 9  }\\\
            e^{-i 2 \pi(2(2)) / 9  }\\\
            e^{-i 2 \pi(2(3)) / 9  }\\\
            e^{-i 2 \pi(2(4)) / 9  }\\\
            e^{-i 2 \pi(2(5)) / 9  }\\\
            e^{-i 2 \pi(2(6)) / 9  }\\\
            e^{-i 2 \pi(2(7)) / 9  }\\\
            e^{-i 2 \pi(2(8)) / 9  }\\\
            e^{-i 2 \pi(2(9)) / 9  }\\\
            \end{array}\right]" 
        ),
        MathTex(r"e^{-i 2 \pi(2(0)) / 19")
    ]


#Almost Fourier Transform - 直坐标到极坐标,然后扭圈圈
class ContinuousFourier(Scene):
    def construct(self):
        #### Global variables ####
        ## Duration of sound wave
        second = 3
        y_scale = 0.5
        a = TAU/second*y_scale
        Da = DecimalNumber(a)
        
        #function
        f = lambda x: y_scale*np.cos(3*2*PI*x)+y_scale

        #### manim_graph ####
        axes = Axes(
            x_range=[0 , second , 1],
            y_range=[0, 1.1, 1],
            x_length=(7+1/9)*2*1.8,
            y_length=4*3/4,
            axis_config={"include_numbers": True},
        )
        polar_axix = PolarPlane(radius_max=1,size=5)

        normal_graph = axes.plot(f,color=YELLOW)
        polar_graph = polar_axix.plot_parametric_curve(
            lambda t : [
                +np.cos(a*t) * (f(t)),
                -np.sin(a*t) * (f(t)),
                0
            ],t_range=[0,second],color=BLUE
        )

        group1 = VGroup(axes,normal_graph)
        group1.scale(0.5).to_edge(UP)
        
        axes_label = axes.get_axis_labels()
        
        upfunc = lambda obj : obj.become(polar_axix.plot_parametric_curve(
            lambda t : [
                +np.cos(Da.get_value()*t) * (f(t)),
                -np.sin(Da.get_value()*t) * (f(t)),
                0
            ],
            t_range=[0,second],
            color=BLUE
        ))
        polar_graph.add_updater(upfunc)

        group2 = VGroup(polar_axix,polar_graph)
        group2.to_edge(DL)


        ########################################################
        #                  Start Animation                     #
        ########################################################

        self.play(Write(Da))
        self.add(axes,polar_axix,axes_label,normal_graph)
        self.play(ReplacementTransform(normal_graph,polar_graph),
            run_time=3.5,
            path_arc = -TAU*2/3)
        self.wait() 
        self.play(ChangeDecimalToValue(Da,5),runtime=3)
        self.wait()


class DFT_preparation(Scene):
    def construct(self):
        # After zoom in in Lib 散点图作为背景,虚化。前面显示以下。
        tex = Text("Dicrete Fourier Transform")
        formula = VGroup(*formula_set.formula_002)
        formula.arrange(DOWN,aligned_edge=LEFT,buff=0.8)

        second = 1
        y_scale = 0.5
        f = lambda x: y_scale*np.cos(30 * x)+y_scale
        ax = Axes(
            x_range=[0 , second , 1],
            y_range=[0, 1.1, 1],
            x_length=(7+1/9)*2*1.8,
            y_length=4*3/4,
            axis_config={"include_numbers": True},
        ).to_edge(DOWN)
        wave = ax.plot(f,color=YELLOW)
        group = VGroup(ax,wave).scale(0.5)
        ########################################################
        #                   Start Animation                    #
        ########################################################

        self.play(FadeIn(tex))
        self.wait()
        self.play(tex.animate.to_edge(UL),FadeIn(formula))
        self.wait()
        self.play(FadeOut(formula),FadeIn(group))
        self.wait()


class PlotDots(Scene):
    def Create_Dot_Set(self,axes,sample,Vg,run_time=1):
        dots_set = []
        _len_sample = int(len(sample))
        for x in range(_len_sample):
            dots_set.append(Dot(radius=0.02,color=BLUE_A,fill_opacity=0.8))
            dots_set[x].move_to(axes.c2p(x,sample[x]))
            self.add(dots_set[x])
            Vg.add(dots_set[x])
            ##如果需要逐个点展示,请取消下行注释即可
            # self.play(FadeIn(dots_set[x]),run_time=run_time/_len_sample)
        return dots_set

    def construct(self):
        ########################################################
        #                     GET SAMPLE                       #
        ########################################################
        sample,_abs_big_ = sample_set.get_winter_wav()
        windows_dot_num = 2048
        shift = 10000

        sample_part=sample[shift:shift+windows_dot_num]
        _big_ = max([abs(max(list(sample_part))),abs(min(list(sample_part)))])
        
        
        print("样本点总数量:"+str(len(sample))+"\n当前节选样本区域:"+str(shift)+","+str(shift+windows_dot_num))

        #### manim_graph ####
        axes = Axes(x_range=(0,windows_dot_num+1,512),
                y_range=(-_big_,_big_,round((_big_)/2,2)),
                axis_config={"include_numbers": True},)
        #np.hanning(windows_dot_num)

        ax_TOTAL = VGroup(axes)
        dots_set = self.Create_Dot_Set(axes,sample_part,ax_TOTAL,run_time=1)

        formula_004 = formula_set.formula_004.to_edge(LEFT).scale(0.5)
        
        ########################################################
        #                   Start Animation                    #
        ########################################################
        self.add(axes)#Add coordinates()
        self.play(Write(formula_004),ax_TOTAL.animate.next_to(formula_004,RIGHT))
        _tc = 0 #temp Int_counter
        _ts=[] #temp Animation_set
        for dot in dots_set:
            if _tc <= 9 * 2:
                _ts.append(Transform(dot,formula_004[0][18+_tc:20+_tc]))
            _tc = _tc +2
        self.play(*_ts,run_time=3)
        self.wait()


class FormulaTest(Scene):
    def construct(self):
        formula_002 = formula_set.formula_002[0].shift(UP)
        formula_003 = formula_set.formula_002[1].next_to(formula_002, DOWN)

        formula_002[0][11:13].color=YELLOW 

        ########################################################
        #                  Start Animation                     #
        ########################################################
        self.add(formula_002[0],formula_003) 
        self.play(Write(formula_002[0]), Write(formula_002[1]), run_time=2)
        self.play(formula_002[0][11:13].animate.set_color(YELLOW))
        self.play(Wiggle(formula_002[0][11:13]))
        self.play(Indicate(formula_002[0][11:13]))  
        self.wait()

#连续图像上打点,然后扭动
class DFT_Illustration(Scene):

    def construct(self):
        #### Global variables ####
        ## Duration of sound wave
        second = 3
        ## Winding frequency
        a = 1
        Da = DecimalNumber(a)
        ## Ini Dot
        NUM_OF_DOT = 12
        
        #### formulas ####
        formula_004 = formula_set.formula_004.to_edge(RIGHT)
        formula_006 = formula_set.formula_006
        formula_006[0].next_to(formula_004,LEFT)

        #### functions ####
        f = lambda x: 0.5*np.cos(3*2*PI*x)+0.5

        Wind_f =lambda t : [
                +np.cos(Da.get_value()*t) * (f(t)),
                -np.sin(Da.get_value()*t) * (f(t)),
                0
            ]

        #### manim_graph ####
        ax = PolarPlane(radius_max=1,size=7)

        #### Curve Mobject ####
        def _get_curve_graph_(func):
            return ax.plot_parametric_curve(
                func,
                t_range=[0,second],
                color=PINK)
        curve = _get_curve_graph_(Wind_f)

        #### Dot Mobject ####
        def _set_plot_dot_(D_set,curve):
            for value in range(NUM_OF_DOT):
                position = ax.i2gp(graph=curve,x=value*PI/NUM_OF_DOT)
                D_set.append(Dot(color=YELLOW).move_to(position))
        _dot_set = []
        _set_plot_dot_(_dot_set,curve)

        ########################################################
        #                  UPDATE FUNCTION                     #
        ########################################################
        
        def upfunc(curve):
            curve.become(_get_curve_graph_(Wind_f))

        def up_dots(curve):
            new_dot_set = []
            _set_plot_dot_(new_dot_set,curve)
            for dot,new_dot in zip(_dot_set,new_dot_set):
                dot.move_to(new_dot)
            self.add(*_dot_set)

        ####Add updater####
        curve.add_updater(up_dots)
        curve.add_updater(upfunc)


        ########################################################
        #                  Start Animation                     #
        ########################################################
        #self.play(Write(formula_004),Write(formula_006[0]))
        #self.play(FadeOut(formula_004,formula_006[0]))

        self.add(ax, curve)
        self.play(ChangeDecimalToValue(Da,15,rate_func=rate_functions.linear),run_time=20)

        
class DFT_RealData(Scene):
    def Create_DotSet_Polar(self,axes,sample,Vg,freq=0,run_time=1):
        dots_set = []
        _len_sample = int(len(sample))
        for x in range(_len_sample):
            dots_set.append(Dot(radius=0.02,color=BLUE_A,fill_opacity=0.8))
            dots_set[x].move_to(axes.polar_to_point(sample[x],x/_len_sample*freq))
            Vg.add(dots_set[x])
        return dots_set

    def construct(self):
        ########################################################
        #                     GET SAMPLE                       #
        ########################################################
        sample,_abs_big_ = sample_set.get_winter_wav()
        windows_dot_num = 512
        shift = 10000

        sample_part=abs(sample[shift:shift+windows_dot_num])
        _big_ = max([abs(max(list(sample_part))),abs(min(list(sample_part)))])
        
        print("number of sample:"+str(len(sample))+"\ncurrent interval:"+str(shift)+","+str(shift+windows_dot_num))

        #### manim_graph ####
        polar_axix = Axes(x_range=(-_big_,_big_),
                y_range=(-_big_,_big_),
                x_length=8,y_length=8,
                axis_config={"include_numbers": True})
        graph_total = VGroup(polar_axix)

        polar_data = self.Create_DotSet_Polar(polar_axix, sample_part,graph_total)
        
        ########################################################
        #                  Start Animation                     #
        ########################################################
        
        self.add(polar_axix,*polar_data)
        
        旋转圈数 = 3
        播放倍数 = 1
        _精细度_ = config.frame_rate*旋转圈数/播放倍数
        for x in range(int(_精细度_)+1):
            new_dots=self.Create_DotSet_Polar(polar_axix, sample_part,graph_total,(x)/(_精细度_)*TAU*旋转圈数)#即绕一个圈中间有多少帧
            count=-1;ani_set=[]
            for obj in polar_data:
                count=count+1
                ani_set.append(Transform(obj,new_dots[count]))
            self.play(*ani_set,run_time=1/config.frame_rate,rate_func=rate_functions.linear)
        

class STFT(Scene):
    def construct(self):
        self.wait()
        # formula_004a = MathTex(r"e^{-i 2 \pi(2(0)) / 19")
        # self.add_subcaption("Hello sub!", duration=1)
        # self.play(Write(formula_004a))



class M_Shift(Scene):
    def Create_Dot_Set(self,axes,sample,Vg,run_time=1):
        dots_set = []
        _len_sample = int(len(sample))
        for x in range(_len_sample):
            dots_set.append(Dot(radius=0.02,color=BLUE_A,fill_opacity=0.8))
            dots_set[x].move_to(axes.c2p(x,sample[x]))
            self.add(dots_set[x])
            Vg.add(dots_set[x])
        return dots_set

    def Create_DotSet_Polar(self,axes,sample,Vg,freq=0,run_time=1):
        dots_set = []
        _len_sample = int(len(sample))
        for x in range(_len_sample):
            dots_set.append(Dot(radius=0.02,color=BLUE_A,fill_opacity=0.8))
            dots_set[x].move_to(axes.polar_to_point(sample[x],x/_len_sample*freq))
            Vg.add(dots_set[x])
        return dots_set
#方案:
#1、先往左边移动,然后Transform到新的点集
#2、直接Transform,但是就是担心transform大量Mobject消耗时间
#3、删除点集合,但是方法失效

    def construct(self):
        ########################################################
        #                     GET SAMPLE                       #
        ########################################################
        sample,_abs_big_ = sample_set.get_winter_wav()
        windows_dot_num = 4096
        shift = 10000



        sample_part=sample[shift:shift+windows_dot_num]
        _big_ = max([abs(max(list(sample_part))),abs(min(list(sample_part)))])
        
        
        print("number of sample:"+str(len(sample))+"\ncurrent interval:"+str(shift)+","+str(shift+windows_dot_num))

        #### manim_graph ####
        axes = Axes(x_range=(0,windows_dot_num+1,512),
                y_range=(-_big_,_big_,round((_big_)/2,2)),
                axis_config={"include_numbers": True},)

        
        text_pos = VGroup(Text('Time Domain x_range:',font_size=22),
                          Text('['+str(shift)+','+str(shift+windows_dot_num)+']',font_size=22))

        text_pos.arrange(DOWN,aligned_edge=ORIGIN,buff=0.2).to_edge(UP)
        
        #np.hanning(windows_dot_num)

        ax_TOTAL = VGroup(axes).next_to(text_pos,DOWN)
        dots_set = self.Create_Dot_Set(axes,sample_part,ax_TOTAL)
        
        ########################################################
        #                   Start Animation                    #
        ########################################################
        self.add(ax_TOTAL,text_pos)#Add coordinates()

        

        self.wait()