精华内容
下载资源
问答
  • 根据大名鼎鼎得AudioCompare (python2.7代码)转化成c++代码,使用了libfftw算学库,网上相关资源非常少,特意分享。代码用vs2017编译调试
  • 音频相似度对比 Demo

    万次阅读 多人点赞 2015-11-24 16:06:06
    简单的音频相似度对比 Demo环境AndroidStudio、MATLAB、Audacity 基本思路和流程1. 录音,保存音频数据 2. 从二进制文件中获取音频原始数据 3. 音频滤波 4. 计算音频信号短时能量 5. 截取音频信号有效数据 6. 对对比...

    #简单的音频相似度对比 Demo

    ##环境
    AndroidStudio、MATLAB、Audacity
    ##基本思路和流程
    1. 录音,保存音频数据
    2. 从二进制文件中获取音频原始数据
    3. 音频滤波
    4. 计算音频信号短时能量
    5. 截取音频信号有效数据
    6. 对对比音频数据进行同上操作
    7. 计算标准音频与对比音频数据的余弦距离

    ##核心代码

    	import java.io.DataInputStream;
    	import java.io.IOException;
    	
    	/**
    	 * Created by lzy on 2015/11/18.
    	 */
    	public class AudioDataOperate {
    	
    	    public static final int TYPE_16BIT = 1;
    	    public static final double DATA_START_VALUE = 0.025;
    	    public static final double DATA_END_VALUE = 0.025;
    	
    	    /**
    	     * 按编码类型提取音频数据
    	     *
    	     * @param dis
    	     * @param size
    	     * @param type
    	     * @return
    	     */
    	    public static short[] getAudioData(DataInputStream dis, int size, int type) {
    	        short[] audioData = new short[size];
    	        try {
    	            byte[] tempData = new byte[2];
    	            long audioDataSize = 0;
    	            while (dis.read(tempData) != -1) {
    	                // 每16位读取一个音频数据
    	                audioData[(int) audioDataSize] = (short) (((tempData[0] & 0xff) << 8) | (tempData[1] & 0xff));
    	                audioDataSize++;
    	                if (audioDataSize == size) {
    	                    break;
    	                }
    	            }
    	        } catch (IOException e) {
    	            e.printStackTrace();
    	        }
    	        return audioData;
    	    }
    	
    	    /**
    	     * 归一化
    	     */
    	    public static double[] normalize(short[] data) {
    	        short max = findMax(data);
    	        double[] result = new double[data.length];
    	        for (int i = 0; i < data.length; i++) {
    	            result[i] = ((double) data[i] / max);
    	        }
    	        return result;
    	    }
    	
    	    /**
    	     * 归一化
    	     */
    	    public static double[] normalize(double[] data) {
    	        double max = findMax(data);
    	        double[] result = new double[data.length];
    	        for (int i = 0; i < data.length; i++) {
    	            result[i] = data[i] / max;
    	        }
    	        return result;
    	    }
    	
    	    /**
    	     * 自身点乘
    	     *
    	     * @return
    	     */
    	    public static double[] dotProduct(double[] data) {
    	        double[] result = new double[data.length];
    	        for (int i = 0; i < data.length; i++) {
    	            result[i] = data[i] * data[i];
    	        }
    	        return result;
    	    }
    	
    	    /**
    	     * 查找最大值
    	     *
    	     * @param data
    	     * @return
    	     */
    	    private static short findMax(short[] data) {
    	        short max = data[0];
    	        for (int i = 0; i < data.length; i++) {
    	            if (max < Math.abs(data[i])) {
    	                max = (short) Math.abs(data[i]);
    	            }
    	        }
    	        System.out.println("max :  " + max);
    	        return max;
    	    }
    	
    	    /**
    	     * 查找最大值
    	     *
    	     * @param data
    	     * @return
    	     */
    	    private static double findMax(double[] data) {
    	        double max = data[0];
    	        for (int i = 0; i < data.length; i++) {
    	            if (max < Math.abs(data[i])) {
    	                max = Math.abs(data[i]);
    	            }
    	        }
    	        System.out.println("max :  " + max);
    	        return max;
    	    }
    	
    	    /**
    	     * 生成窗函数
    	     */
    	    public static double[] generateWindows(int N, int i) {
    	        // 使用最简单的矩形窗
    	        double[] wins = new double[i * N];
    	        for (int j = 0; j < i * N; j++) {
    	            wins[j] = 1;
    	        }
    	        return wins;
    	    }
    	
    	    /**
    	     * 生成窗函数   hamming窗
    	     */
    	    public static double[] generateHammingWindows(int N, int i) {
    	        // 使用最简单的矩形窗
    	        double[] wins = new double[i * N];
    	        for (int j = 0; j < i * N; j++) {
    	            wins[j] = 0.54 - 0.46 * (Math.cos(2 * Math.PI * j / (i * N)));
    	        }
    	        return wins;
    	    }
    	
    	
    	    /**
    	     * 短时能量
    	     */
    	    public static void shortTimeEnergy() {
    	    }
    	
    	    /**
    	     * 计算卷积
    	     *
    	     * @param self  数据段
    	     * @param other 窗函数 (默认窗函数的长度远小于数据长度)
    	     * @return
    	     */
    	    public static double[] conv(double[] self, double[] other) {
    	        double[] result = new double[self.length + other.length - 1];
    	        double current = 0;
    	        for (int i = 0; i < self.length + other.length - 1; i++) {
    	            current = 0;
    	            for (int j = 0; j <= i; j++) {
    	                if (j >= self.length || i - j >= other.length) {
    	                    continue;
    	                }
    	                //TODO 去除一些数据的运算提高效率
    	
    	                current += self[j] * other[i - j];
    	            }
    	            result[i] = current;
    	        }
    	        return result;
    	    }
    	
    	    /**
    	     * 计算余弦距离 dot(En_compare, En_standard)/(norm(En_compare)*norm(En_standard))
    	     *
    	     * @param standard
    	     * @param comapre
    	     * @return
    	     */
    	    public static double cosineDistance(double[] standard, double[] comapre) {
    	        double dot = 0;
    	        double normStandard = 0;
    	        double normCompare = 0;
    	        for (int i = 0; i < standard.length; i++) {
    	            dot += standard[i] * comapre[i];
    	            normStandard += standard[i] * standard[i];
    	            normCompare += comapre[i] * comapre[i];
    	        }
    	        double distance = dot / (Math.sqrt(normStandard) * Math.sqrt(normCompare));
    	        return distance;
    	    }
    	
    	    /**
    	     * 通过阈值得到音频有效数据开始的下标
    	     */
    	    public static int findDataStartIndex(double[] audioData) {
    	        for (int i = 0; i < audioData.length; i++) {
    	            if (audioData[i] > DATA_START_VALUE) {
    	                return i;
    	            }
    	        }
    	        return -1;
    	    }
    	
    	    /**
    	     * 通过阈值得到音频有效数据结束的下标
    	     */
    	    public static int findDataEndIndex(double[] audioData) {
    	        for (int i = audioData.length - 1; i >= 0; i--) {
    	            if (audioData[i] > DATA_END_VALUE) {
    	                return i;
    	            }
    	        }
    	        return -1;
    	    }
    	
    	    /**
    	     * 截取音频有效数据(通过阈值获得的数据前后开始结束的下标来截取数据)
    	     *
    	     * @param audioData
    	     * @return
    	     */
    	    public static double[] getUsefulData(double[] audioData, int start, int end) {
    	        double[] usefulData = new double[end - start];
    	        for (int i = start; i < end; i++) {
    	            usefulData[i - start] = audioData[i];
    	        }
    	        return usefulData;
    	    }
    	
    	    /**
    	     * 截取音频有效数据(通过阈值获得的数据前后开始结束的下标来截取数据)
    	     *
    	     * @param audioData
    	     * @return
    	     */
    	    public static double[] getUsefulData(double[] audioData) {
    	        int start = AudioDataOperate.findDataStartIndex(audioData);
    	        int end = AudioDataOperate.findDataEndIndex(audioData);
    	        System.out.println("dataLength   " + audioData.length + "     getUsefulData    " + "start: " + start + "   end : " + end);
    	        return getUsefulData(audioData, start, end);
    	    }
    	
    	    /**
    	     * 处理对比音频使其与标准音频长度相同(通过阈值获得的数据开始下标截取与标准音频相同长度的音频数据)
    	     *
    	     * @param audioData
    	     * @return
    	     */
    	    public static double[] dealCompareData(double[] audioData, int start, int length) {
    	        double[] usefulData = new double[length];
    	        for (int i = start; i < start + length; i++) {
    	            //从有效音频开始点截取标准音频的长度的音频可能超过对比音频长度边界
    	            if (i >= audioData.length) {
    	                usefulData[i - start] = 0;
    	            } else {
    	                usefulData[i - start] = audioData[i];
    	            }
    	        }
    	        return usefulData;
    	    }
    	
    	    /**
    	     * 处理对比音频使其与标准音频长度相同(通过阈值获得的数据开始下标截取与标准音频相同长度的音频数据)
    	     *
    	     * @param audioData
    	     * @return
    	     */
    	    public static double[] dealCompareData(double[] audioData, int length) {
    	        int start = AudioDataOperate.findDataStartIndex(audioData);
    	        System.out.println("dealCompareData: " + audioData.length + "   " + start + "   " + length);
    	        return dealCompareData(audioData, start, length);
    	    }
    	
    	    /**
    	     * 滤波(差分方程)
    	     *
    	     * @param audioData
    	     */
    	    public static double[] filter(double[] audioData, double b0, double b1) {
    	        double[] result = new double[audioData.length];
    	        result[0] = audioData[0];
    	        for (int i = 1; i < audioData.length; i++) {
    	            result[i] = b0 * audioData[i] + b1 * audioData[i - 1];
    	        }
    	        return result;
    	    }
    	}
    

    ##遇到的问题
    1. MATLAB、Audacity导入音频原始数据时文件的大尾端、小尾端问题

    ##改进内容:
    1. 优化短时能量,卷积计算过程,提高计算效率
    2. 改进滤波方法
    ##项目截图
    这里写图片描述
    ##项目地址
    https://github.com/xdyuchen/AudioScore

    展开全文
  • AudioCompare 音频相似度比较,匹配上会返回匹配的数值
  • mp3音频文件相似度比对软件

    热门讨论 2014-08-20 16:39:23
    mp3 音频文件 相似度 比对软件
  • 声纹相似度对比vb源代码
  • 2)调用代码(参数60表示,相似度达到60%则算及格,程序将正整数,否则返回负整数) WAVECompare.WAVEObject objWAV = new WAVECompare.WAVEObject(); int _result = objWAV.ToCompare(60, @"E:\11.wav", @"E:\22....
  • python 音频文件 转列表 比对相似度

    千次阅读 2019-05-03 14:01:01
    我们知道,图片,文字,音频都可以转成数据存储在内存中,下面我给大家分享一个音频文件转义成列表内存,然后俩个列表对比相似度,来判断音频文件间的对比。话不多说,代码伺候; #-*-coding:utf-8-*- import os ...

    我们知道,图片,文字,音频都可以转成数据存储在内存中,下面我给大家分享一个音频文件转义成列表内存,然后俩个列表对比相似度,来判断音频文件间的对比。话不多说,代码伺候;

    #-*-coding:utf-8-*-
    import os
    import re
    import wave
    import numpy as np
    import pyaudio
    
    #音频比对子体时间小于母体
    class Voice()
    	def __init__(self):
    		self.name=[(x,x,x,x).....]    #音频文件转码后
    
    	def loaddata(self,filepath):
    		if type(filepath)!=str:
    			print('文件的路径不正确')
    			return False
    		 p1=re.compile('\.wav')
    		 if p1.findall(filepath) is None:
    		 	print('请确保文件的格式属于wav')
    		 	return False
    		 try:
    		 	f=wave.open(filepath,'rb')
    		 	parmas=f.getparams()
    		 	self.nchannels,self.sampwidth,self.framerate,self.nframes=parmas[:4]
    		 	str_data=f.readframes(self.nframes)
    		 	self.wave_data=np.fromstring(str_data,dtype=np.short)
    		 	self.wave_data=self.wave_data.T
    		 	f.close()
    		 	self.name=os.path.basename(filepath) #记录下文件名
    		 	return True 
    		 except:
    		 	print(‘File error!’)
    
    	def fft(self,frames=40):
    		block=[]
    		fft_block=[]
    		high_point=[]
    		blocks_size=self.framerate/frames  #为每一块的frame数量
    		blocks_num=self.nframes/blocks_size #将音频分块的数量
    		for i in range(0,len(self.wave_data[0]))-int(blocks_size),int(blocks_size):
    			block.append(self.wave_data[0][i:i+int(blocks_size)])
    			fft_blocks.append(np.abs(np.fft.fft(self.wave_data[0][i:i]+int(blocks_size))))
    			high_point.append((np.argmax(fft_blocks[-1][:40]),
    			np.argmax(fft_blocks[-1][40:80])+40,
    			np.argmax(fft_blocks[-1][80:120])+80,
    			np.argmax(fft_blocks[-1][120:180])+120,))
    			return high_point
    
    	def play(self,filepath):
    		chunk=1024
    		wf=wave.open(filepath,'rb')
    		p=pyaudio.PyAudio()
    		#打开声音输出流
    		stream=p.open(format=p.get_format_from_width(wf.getsampwidth()),
    		channels=wf.getnchannels(),
    		rate=wf.getframerate(),
    		output=True)
    		#写声音输出流进行播放
    		while True:
    			data=wf.readframes(chunk)
    			if data=="":
    				break
    			stream.write(data)
    			stream.close()
    			p.terminate()
    
    	def fp_compare(self,search_fp,type):
    		'''type决定音频比对类型'''
    		if type=="clock":
    			match_fp=self.clock
    		.......
    		if len(search_fp)>len(match_fp):
    			return 0;
    		max_similar=0
    		search_fp_len=len(search_fp)
    		match_fp_len=len(match_fp)
    		for i in range(match_fp_len-search_fp_len):
    			temp=0
    			for j in range(search_fp_len):
    				flag=0
    				for x in range(4):
    					if match_fp[i+j][x]<=search_fp[j][x]<=match_fp[i+j][x]:
    						flag=flag+1
    						if flag==4:
    							temp+=1
    						if temp>max_similar:
    							max_similar=temp
    		return max_similar
    
    if __name__='__main__':
    	p=Voice()
    	#加载具体音频路径
    	p.loaddata("D:\\") 	
    	#比对音频能量值 大于1为比对成功 等于0为比对失败,代表音频不匹配
    	print(p.fp_compare(p.fft())) is 0)
    
    展开全文
  • 基于android的音频信号分析并显示波形图对比结果,增加滤波功能,短时能量,对比分析
  • 歌曲的相似度分析和听歌识曲原理核心思路基本一致,都是提取歌曲的声纹进行判断,提取声纹的方法,这里就要搬出我们大学学过的傅里叶变换了 关于傅里叶变换的普及,可以参考链接 ... 这里听歌识曲,是有一个比较出名...

    歌曲的相似度分析和听歌识曲原理核心思路基本一致,都是提取歌曲的声纹进行判断,提取声纹的方法,这里就要搬出我们大学学过的傅里叶变换了

    关于傅里叶变换的普及,可以参考链接

    https://www.cnblogs.com/h2zZhou/p/8405717.html

    这里听歌识曲,是有一个比较出名的开源项目的,叫dejavu,GitHub的地址是,它的特点是识别快,可能只需要试听几秒钟,就可以准确的识别出源歌曲,但是缺点是占用空间较大,这里我做了一个测试,使用dejavu提取了5个歌曲的声纹,查询MySQL这个表的空间使用就有28M (29982720/1024/1024),基本相当于5首mp3歌曲的大小

    为什么dejavu生成的歌曲指纹,这个我们后面再说,有没有相对比较节约空间的方法呢,也是有的(方案参考互联网,当然也离不开FFT,即傅里叶变换)

    下面我想讲一下这个方法:

    首先,我们要对整个歌曲进行分块,比如每秒100分块

    其次,对每一个分块进行FFT,接着对频域的结果进行区间划分,取出每一个区间的最大值的坐标,这个坐标,就是歌曲片段的特征值

    最后将特征值按顺序排列,就是整个歌曲的指纹了

    如果需要对比两首歌曲的相似程度,只需要按顺序比较特征值的相似程度,根据相似度来判断即可

    之所以需要对歌曲分块,就是为了记录歌曲的时间序列,如果直接对整个歌曲进行FFT,就损失了时间的关系,另外这个结果也非常的杂乱,有兴趣的可以试试,然后使用matplotlib输出结果图查看

    这里我使用程序中导入了3首歌曲,提取了指纹,数据库的占用大小是278528bytes,0.26M,这里需要说一下,我这里是直接存储的字符串结果,并没有压缩,所以实际压缩后甚至可以更小

     

    接下来我们就看一下,为什么空间占用的差别在哪里

     

     

     

     

     

     

    展开全文
  • python实现歌曲相似度比较(超详细,总有收获)

    千次阅读 热门讨论 2020-01-23 13:10:05
    python实现歌曲相似度比较 2019/9/20 最近学信号与系统,想着弄个小项目来提高学习兴趣。特此记录一下。 这是大概想到的准备工作,一边推进,一边学吧!!! 2019/9/21 频域信号处理 FFT变换所得的复数的...

    python实现歌曲相似度比较

    2019/9/20
    最近学信号与系统,想着弄个小项目来提高学习兴趣。特此记录一下。
    这是大概想到的准备工作,一边推进,一边学吧!!!
    大概需要的准备
    2019/9/21

    频域信号处理

    FFT变换所得的复数的含义:

    • 下标为0的实数表示时域信号的直流部分
    • 下标为i的复数为a+bj表示时域信号中周期为N/i个取样值的正弦波和余弦波的成分,其中a表示余弦波形的成分,b表示正弦波形的成分
    • 复数的模的两倍为对应频率的余弦波的振幅
    • 复数的辐角表示对应频率的余弦波的相位
    import numpy as np
    from scipy.fftpack import fft, ifft
    import matplotlib.pyplot as plt
    from matplotlib.pylab import mpl
    x = np.arange(0, 2*np.pi, 2*np.pi/128)
    y = 0.3*np.cos(x) + 0.5*np.cos(2*x+np.pi/4) + 0.8*np.cos(3*x-np.pi/3) + np.sin(4*x) + np.cos(x)
    yf = fft(y)/len(y)
    print(np.array_str(yf[:5], suppress_small=True))
    for ii in range(0, 5):
        print(np.abs(yf[ii]), np.rad2deg(np.angle(yf[ii])))
    

    运行上述程序可以观察得到以上结论

    合成时域信号

    需要着重解释的是多个余弦信号合成任意时域信号的过程:

    FFT转换得到的N个复数组成的数组A, A i A_i Ai表示第 i i i个子信号,其中 i = 0 i=0 i=0的子信号表示直流信号,且 R e ( A i ) Re(A_i) Re(Ai)表示直流信号的振幅。 2 × R e ( A i ) = A m p l i t u d e ( s i g n a l s i n ) 2 \times Re(A_i) = Amplitude(signal_{sin}) 2×Re(Ai)=Amplitude(signalsin)
    2 × I m ( A i ) = A m p l i t u d e ( s i g n a l c o s ) 2 \times Im(A_i) = Amplitude(signal_{cos}) 2×Im(Ai)=Amplitude(signalcos)
    利用前 k k k个自信号合成过程用数学表达式表示:
    2 × ∑ i = 1 k { R e ( A i ) c o s ( i t ) − I m ( A i ) s i n ( i t ) } + R e ( A 0 ) 2\times \sum_{i=1}^{k}\{Re(A_i)cos(it)-Im(A_i)sin(it)\}+Re(A_0) 2×i=1k{Re(Ai)cos(it)Im(Ai)sin(it)}+Re(A0)
    代码如下所示

    import numpy as np
    from scipy.fftpack import fft, ifft
    import matplotlib.pyplot as plt
    from matplotlib.pylab import mpl
    mpl.rcParams['font.sans-serif'] = ['SimHei']  #显示中文
    mpl.rcParams['axes.unicode_minus'] = False  #显示负号
    # x = np.arange(0, 2*np.pi, 2*np.pi/128)
    # y = 0.3*np.cos(x) + 0.5*np.cos(2*x+np.pi/4) + 0.8*np.cos(3*x-np.pi/3) + np.sin(4*x) + np.cos(x)
    # yf = fft(y)/len(y)
    # print(np.array_str(yf[:5], suppress_small=True))
    # for ii in range(0, 5):
    #     print(np.abs(yf[ii]), np.rad2deg(np.angle(yf[ii])))
    def triangle_wave(size):
        x = np.arange(0, 1, 1.0/size)
        y = np.where(x < 0.5, x, 0)
        y = np.where(x >= 0.5, 1-x, y)
        return x, y
    ###
    def fft_comnbine(bins, n, loops):
        length = len(bins)*loops
        data=np.zeros(length)
        index=loops*np.arange(0, 2*np.pi, (2*np.pi)/length)
    
        for k, p in enumerate(bins[:n]):
            if k != 0:
                p *= 2
            ###合成时域信号的过程
            data += np.real(p)*np.cos(k*index)
            data -= np.imag(p)*np.sin(k*index)
        return index, data
    fft_size = 256
    ###对三角波进行FFT
    x, y = triangle_wave(fft_size)
    fy = fft(y)/fft_size
    loops = 4
    y = np.tile(y, (1, loops))
    print(y.shape)
    y.shape = (fft_size*loops, )#画图python的特殊癖好
    ###
    fig, axes = plt.subplots(2, 1, figsize=(8, 6))
    eps = 1e-5
    # axes[0].plot(np.clip(20*np.log10(np.abs(fy[:20])+eps), -120, 120), "o")
    axes[0].plot(np.abs(fy[:20]), "o")
    axes[0].set_xlabel(u"频率窗口(frequency bin)")
    axes[0].set_ylabel(u"幅值(dB)")
    axes[1].plot(y, label=u"原始三角波", linewidth = 2)
    for ii in [0, 1, 3, 5, 7, 9]:
        index, data = fft_comnbine(fy, ii+1, loops)
        axes[1].plot(data, label="N=%s" % ii, alpha=0.6)
    print(index[:20])
    axes[1].legend(loc="best")
    plt.show()
    
    理论部分后面学了信号与系统在深究吧

    哈——现在的我已经学完信号与系统了,回复几个一开始学习遇到的问题。

    1. 复数的模的两倍为什么对应频率的余弦波的振幅?
      ans:若 x ( t ) x(t) x(t)为实信号,那么
      由傅里叶变换:
      f n = F { x ( t ) } f_n = \mathscr{F}\{x(t)\} fn=F{x(t)}
      得到推导过程中运用了欧拉公式使得余弦波的振幅乘上1/2,而相位不变。

    2. 为什么周期为N的离散信号,它的傅里叶变换的周期也是N?
      ans:这个就是离散信号的傅里叶变换的周期性。可以在奥本海默的信号与系统的傅里叶性质表看到。

    顺便提及奈奎斯特频率
    在采样定理中,采样频率必须大于 2 ω m 2 \omega_m 2ωm,这个 2 ω m 2\omega_m 2ωmj就称作奈奎斯特频率,目的是防止采样信号的频率防止重叠,其中 ω m \omega_m ωm为原始信号的频域 ω \omega ω的最大值。

    利用pydub和ffmpeg处理音频

    写在前面:
    RuntimeWarning: Couldn’t find ffmpeg or avconv - defaulting to ffmpeg, but may not work 解决办法——ffmpeg的bin 目录添加到path变量里,注意是path变量而不仅仅是简单的加到系统变量中!!!然后重启。

    一、将mp3转换为wav格式,并将歌曲划分为几个部分

    说在前面
    1.将歌曲划分为几部分主要是为了将特征的时间顺序体现出来
    2. wav:非压缩文件格式。
    3.mp3:压缩文件格式。
    代码如下:

    tail, track = os.path.split(mp3_path)
    song_name = track.split('.')
    wav_path = os.path.join(tail, 'w_session', song_name[0]+'.wav')
    sound = AudioSegment.from_file(mp3_path, format='mp3')
    sound.export(wav_path, format='wav')
    

    获取wav文件信息:

    w = wave.open(wav_path)
    params = w.getparams()
    print(params)
    #声道数、量化位数(byte)、采样频率、采样点数 
    nchannels, sampwidth, framerate, nframes = params[:4]
    t = np.arange(0, nframes)*(1/framerate)#文件时间
    strData = w.readframes(nframes)#读取音频,字符串格式
    waveData = np.fromstring(strData,dtype=np.int16)#将字符串转化为int
    #waveData = waveData*1.0/(max(abs(waveData)))#wave幅值归一化
    waveData = np.reshape(waveData,[nchannels, nframes])#双通道数
    

    划分歌曲

    for ii in range(nchannels):
        for jj in range(0, 4):
            end_time = start_time + chunk[jj]
            blockData = waveData[0, start_time*framerate:end_time*framerate]
            start_time = end_time
    

    二、音频特征提取

    按照处理空间区分

    • 要提取的特征 详情请点击
      时域特征:
      线性预测系数、过零率
      频域特征:
      Mel系数、LPC倒频谱系数、熵特征、光谱质心
      时频特征:
      小波系数
    • TOOLS:pyAudioAnalysis
      下载以及安装方法:安装方法
      个人感觉这个工具包满新的,github上有各种issues。issues详见

    同时有一篇论文有对这个工具包有详细的描述:论文

    下面摘抄一部分:
    Feature Extraction
    Audio Features

    1. the audio signal is first divided into short-term windows (frames) and for each frame all 34 features are calculated. This results in a sequence of short-term feature vectors of 34 elements each. Widely accepted short-term window sizes are 20 to 100 ms.
    2. Typical values of the mid-term segment size can be 1 to 10 seconds.
    3. In cases of long recordings (e.g. music tracks) a long-term averaging of the mid-term features can be applied so that the whole signal is represented by an average vector of mid-term statistics.
    4. Extract mid-term features and long-term averages in order to produce one feature vector per audio signal.

    三、计算相似矩阵

    论文中提到:A similarity matrix is computed based on the cosine distances of the individual feature vectors.
    但是在实际操作的过程中发现不同特征的量纲不同,导致用余弦相似度来计算特征相似度不准确。例:

    789
    2.62281350727428e-100-50.5964425626941
    2.29494356256208e-110-50.5964425626941
    4.55467645371887e-110-50.5964425626941

    所以我决定计算不同特征的相对比值,然后取平均值。

    def similarity(v1, v2):
    #   计算平均相似度
        temp = []
        sim = []
        p = 0
        q = 1
        
        for ii in range(v1.shape[0]):
            for jj in range(v1.shape[1]):
                if v1[ii, jj]!=0 or v2[ii, jj]!=0 :
                    temp.append((1 - 
            abs(v1[ii, jj]-v2[ii, jj])/max(abs(v1[ii,
            jj]),abs(v2[ii, jj]))))
                    q += 1
            sim.append(np.mean(temp[p:q]))
            p = q
        print(sim)
        return sim
    

    此外可以尝试马氏距离——参考文章
    下文为部分摘抄。

    • 使用场景:

      1、度量两个服从同一分布并且其协方差矩阵为C的随机变量X与Y的差异程度
      2、度量X与某一类的均值向量的差异程度,判别样本的归属。此时,Y为类均值向量.

    • 马氏距离的优缺点:
      优点:量纲无关,排除变量之间的相关性的干扰
      缺点:不同的特征不能差别对待,可能夸大弱特征

    四、减少运行代码的时间

    之前将歌曲划分为等差序列的长度demo,可计算一个片段的特征就要好久。我等不下去,所以决定想法子降低复杂度。我想到两个办法:

    • 在原来等差序列的片段上随机选取四秒片段,计算特征相似度。如果大于0.5,那么在计算完整片段的特征相似度。
    • 将原来采样频率44.1kHz缩小四倍
    k = 4
    ii = 0
    w_decrease = [[], []]
    #   降低音频分辨率
    for kk in (0, 1):
        while ii < len(w[:, kk]):
            if ii + k < len(w[:, kk]):
                w_decrease[kk].append(np.mean(w[ii:ii+k, kk]))
            else:
                w_decrease[kk].append(np.mean(
                        w[ii:len(w[:, kk])+1, kk]))
            ii = ii + k
    w = w_decrease
    

    五、完整代码

    # -*- coding: utf-8 -*-
    """
    Created on Fri Jan 10 21:51:38 2020
    
    @author: yoona
    """
    import os
    import sys
    import wave
    import numpy as np
    #import struct
    from pydub import AudioSegment
    import matplotlib.pyplot as plt
    from pyAudioAnalysis import audioFeatureExtraction as afe
    import eyed3
    import random
    import math
    
    def Features(path, mode):
        x = wave.open(path)
        params = x.getparams()
        print(params)
    
        if params[0] != 2:
            raise ValueError('通道数不等于2')
    
        strData = x.readframes(params[3])
        w = np.frombuffer(strData, dtype=np.int16)
        w = np.reshape(w,[params[3], params[0]])
        
        k = 4
        ii = 0
        w_decrease = [[], []]
        
        if mode == 'second':
        #   降低音频分辨率
            for kk in (0, 1):
                while ii < len(w[:, kk]):
                    if ii + k < len(w[:, kk]):
                        w_decrease[kk].append(np.mean(w[ii:ii+k, kk]))
                    else:
                        w_decrease[kk].append(np.mean(
                                w[ii:len(w[:, kk])+1, kk]))
                    ii = ii + k
            w = w_decrease
            
        eigen_vector_0 = afe.mtFeatureExtraction(
                w[:, 0], params[2],30.0, 30.0, 2, 2)
        eigen_vector_1 = afe.mtFeatureExtraction(
                w[:, 1], params[2],30.0, 30.0, 2, 2)
        
        return eigen_vector_0, eigen_vector_1
    
    def read_wave(wav_path):
        w = wave.open(wav_path)
        params = w.getparams()
    #    print(params)
    #   声道数、量化位数(byte)、采样频率、采样点数 
        nchannels, sampwidth, framerate, nframes = params[:4]
        
    #   文件时间
        t = np.arange(0, nframes)*(1/framerate)
        strData = w.readframes(nframes)#读取音频,字符串格式
        waveData = np.frombuffer(strData, dtype=np.int16)#将字符串转化为int
        waveData = waveData*1.0/(max(abs(waveData)))#wave幅值归一化
        waveData = np.reshape(waveData,[nframes, nchannels])#双通道数
        
    #    plot the wave
        plt.figure()
        plt.subplot(4,1,1)
        plt.plot(t,waveData[:, 0])
        plt.xlabel("Time(s)")
        plt.ylabel("Amplitude")
        plt.title("Ch-1 wavedata")
        plt.grid('on')#标尺,on:有,off:无
        plt.subplot(4,1,3)
        plt.plot(t,waveData[:, 1])
        plt.xlabel("Time(s)")
        plt.ylabel("Amplitude")
        plt.title("Ch-2 wavedata")
        plt.grid('on')#标尺,on:有,off:无
        plt.show()  
        
    def similarity(v1, v2):
    #   计算平均相似度
        temp = []
        sim = []
        p = 0
        q = 1
        
        for ii in range(v1.shape[0]):
            for jj in range(v1.shape[1]):
                if v1[ii, jj]!=0 or v2[ii, jj]!=0 :
                    temp.append((1 - 
            abs(v1[ii, jj]-v2[ii, jj])/max(abs(v1[ii, jj]),abs(v2[ii, jj]))))
                    q += 1
            sim.append(np.mean(temp[p:q]))
            p = q
        print(sim)
        return sim
    
    def compute_chunk_features(mp3_path):
    # =============================================================================
    # 计算相似度第一步
    # =============================================================================
    #   获取歌曲时长
        mp3Info = eyed3.load(mp3_path)
        time = int(mp3Info.info.time_secs)
        print(time)
        tail, track = os.path.split(mp3_path)
        
    #   创建两个文件夹
        dirct_1 = tail + r'\wavSession'
        dirct_2 = tail + r'\wavBlock'
        if not os.path.exists(dirct_1):
            os.makedirs(dirct_1)
        if not os.path.exists(dirct_2):
            os.makedirs(dirct_2)  
    
    #   获取歌曲名字
        song_name = track.split('.')
    #   转换格式
        wav_all_path = os.path.join(tail, song_name[0]+'.wav')
        sound = AudioSegment.from_file(mp3_path, format='mp3')
        sound.export(wav_all_path, format='wav')
        read_wave(wav_all_path)
    #   划分音频
        gap = 4
        diff = time/10 - 8
        start_time = 0
        end_time = math.floor(diff)
        vector_0 = np.zeros((10, 68))
        vector_1 = np.zeros((10, 68))
        info = []#记录片段开始时间点
        
        for jj in range(5):
            wav_name = song_name[0]+str(jj)+'.wav'
            wav_path = os.path.join(tail, 'wavSession', wav_name)
    #       随机产生四秒片段
            rand_start = random.randint(start_time, end_time) 
            blockData = sound[rand_start*1000:(rand_start+gap)*1000]
    ##       音频切片,时间的单位是毫秒
    #        blockData = sound[start_time*1000:end_time*1000]
            blockData.export(wav_path, format='wav')
            eigVector_0, eigVector_1 = Features(wav_path, [])
            print(jj)# 标记程序运行进程
    #       得到一个片段的特征向量
            vector_0[jj, :] = np.mean(eigVector_0[0], 1)
            vector_1[jj, :] = np.mean(eigVector_1[0], 1)
    #       迭代
            diff = diff + 4
            info.append((start_time, end_time))
            start_time = end_time
            end_time = math.floor(start_time + diff)
            
    #   承上启下
        end_time = start_time 
        
        for kk in range(5, 10):
    #       迭代
            diff = diff - 4
            info.append((start_time, start_time + diff))
            start_time = end_time
            end_time = math.floor(start_time + diff)
            wav_name = song_name[0]+str(kk)+'.wav'
            wav_path = os.path.join(tail, 'wavSession', wav_name)
            
    #       随机产生四秒片段
            rand_start = random.randint(start_time, end_time) 
            blockData = sound[rand_start*1000:(rand_start+gap)*1000]        
    #        blockData = sound[start_time*1000:end_time*1000]
            blockData.export(wav_path, format='wav')
            eigVector_0, eigVector_1 = Features(wav_path, [])
            print(kk)#标记程序运行进程
    #       得到一个片段的特征向量
            
            vector_0[kk, :] = np.mean(eigVector_0[0], 1)
            vector_1[kk, :] = np.mean(eigVector_1[0], 1)
            
        return vector_0, vector_1, info# 双通道各自的特征向量
    
    def Compute_Bolck_Features(info, mp3_path):
    # =============================================================================
    # 计算相似度第二步
    # =============================================================================
    #   获取歌曲时长
        mp3Info = eyed3.load(mp3_path)
        time = int(mp3Info.info.time_secs)
        print(time)
    #   获取歌曲名字
        tail, track = os.path.split(mp3_path)
        song_name = track.split('.')
    #   转换格式
        sound = AudioSegment.from_file(mp3_path, format='mp3')
        vector_0 = np.zeros((len(info), 68))
        vector_1 = np.zeros((len(info), 68))
        
        for kk in range(len(info)):
            #   获取歌曲完整片段的特征
            wav_name = song_name[0]+str(kk)+'.wav'
            wav_path = os.path.join(tail, 'wavBlock', wav_name)
            #   截取完整片段
            blockData = sound[info[kk][0]*1000:info[kk][1]*1000]        
            blockData.export(wav_path, format='wav')
            eigVector_0, eigVector_1 = Features(wav_path, 'second')
            print(kk)#标记程序运行进程
            #   得到一个片段的特征向量
            vector_0[kk, :] = np.mean(eigVector_0[0], 1)
            vector_1[kk, :] = np.mean(eigVector_1[0], 1)
        return vector_0, vector_1
    
    def file_exists(file_path):
        if os.path.splitext(file_path) == '.mp3':
            if os.path.isfile(file_path):
                return file_path
            else:
                raise TypeError('文件不存在')
        else:
            raise TypeError('文件格式错误,后缀不为.mp3')
    
    if __name__ == '__main__':
    
    #for path, dirs, files in os.walk('C:/Users/yoona/Desktop/music_test/'):
    #    for f in files:
    #        if not f.endwith('.mp3'):
    #            continue
    # 把路径组装到一起
    #path = r'C:\Users\yoona\Desktop\musictest'
    #f = 'CARTA - Aranya (Jungle Festival Anthem).mp3'
    #mp3_path = os.path.join(path, f)
    # =============================================================================
    # sa_b:a表示歌曲的序号,b表示歌曲的通道序号
    # =============================================================================
    #s1_0, s1_1, info1= compute_chunk_features(mp3_path) 
    #    path_1 = file_exists(sys.argv[1])
    #    path_2 = file_exists(sys.argv[2])]
        
        path_1 = r'C:\Users\yoona\Desktop\music\薛之谦 - 别.mp3'
        path_2 = r'C:\Users\yoona\Desktop\music\薛之谦 - 最好.mp3'
        
        s1_1, s1_2, info1 = compute_chunk_features(path_1)
        s2_1, s2_2, info2 = compute_chunk_features(path_2)
        
        sim_1 = similarity(s1_1, s2_1)#通道数1
        sim_2 = similarity(s1_2, s2_2)#通道数2
        
        info1_new = []
        info2_new = []
        
        for i, element in enumerate(sim_1):
            if element >= 0.5:
                info1_new.append(info1[i])
                
        if not info1_new:
            pos = np.argmax(sim_1)
            info1_new.append(info1[pos])
        s1_1, s1_2 = Compute_Bolck_Features(info1_new, path_1)
        
        for i, element in enumerate(sim_2):
            if element >= 0.5:
                info2_new.append(info2[i])
    
        if not info2_new:
            pos = np.argmax(sim_2)
            info2_new.append(info2[pos])
        s2_1, s2_2 = Compute_Bolck_Features(info2_new, path_2)
        
        sim_1 = similarity(s1_1, s2_1)#通道数1
        sim_2 = similarity(s1_2, s2_2)#通道数2
    
    

    六、结果分析

    第一组实验对象:
    A:薛之谦 - 最好.mp3
    B:薛之谦 - 别.mp3
    第二组实验对象:
    A:Karim Mika - Superficial Love.mp3
    B: Burgess/JESSIA - Eclipse.mp3
    第三组实验对象:
    A: CARTA - Aranya (Jungle Festival Anthem).mp3
    B: 薛之谦 - 别.mp3

    展开全文
  • 我现在用的python3.7和audioanalysis2.1,运行不了。 出现了如下错误: plt.plot(t, waveData[:, 1]) IndexError: index 1 is out of bounds for axis 1 with size 1 您那里运行成功了吗?
  • 语音相似度匹配c++

    2016-06-19 11:03:27
    语音相似度匹配全过程,c++
  • AudioCompare比较两个音频相似度

    万次阅读 热门讨论 2017-05-25 10:51:03
    AudioCompare比较两个音频相似度项目最近遇到一个问题,两段音频,它们的大小仅相差几个字节,导致文件的md5值不一样,但实际上它们又是相同的音频,需求就是要把这样的音频找出来。从网上找了下,有这样一个库...
  • 如我有N多个音频,每段音频中都出现“多一些润滑,少一些摩擦出自:统一润滑油”的广告词,怎么样在可以快速的在每个音频中找出现出广告词的时间段谢谢大神,可以重金,加我QQ1400580033议价...
  • 比较两个音频文件或音频文件目录以评估它们的相似性。 可能已从另一个文件派生的文件被标记为匹配。 要运行该程序,请输入以下之一: ./audiocompare -f文件1 -f文件2 ./audiocompare -f文件1 -d目录1 ./...
  • 语音相似度打分技术说明【音频质量专题】 ...
  • OpenCV进行图像相似度对比的三种办法
  • Linux 音频player对比

    2021-09-11 17:19:31
    (个人理解:即切换歌曲时,中间不停顿) **Replay Gain:**回放增益(Replay Gain)是一个于2001年7月12日被公开提出的标准,用于将像MP3或Ogg Vorbis等格式的数字化音频的可感知响度进行标准化(Normalize) 处理。...
  • 声音的 声音相似度wavTopng是声音转图片的工具
  • OpenCv相似度比较

    热门讨论 2016-01-27 15:53:06
    OpenCv相似度比较,通过对比两张图片的相似度来判断俩张图片是不是同一张照片
  • 相似性音频比对

    千次阅读 2015-03-09 22:05:47
    (1)比对两个音频的相似程度; (2)判断一个音频跟另外一个音频是否存在公共部分; (3)判断一个音频是否是另外一个音频的一部分。 联系方式:邮箱:xiaobing_qin_china@163.com
  • Java如何实现音频对比

    千次阅读 2012-02-24 10:31:47
    这个可以用FFT(Fast Fourier Transform)将time domain的音频转换到Frequency domain,即得到音频的频谱,在比较两者的频谱即可。比如一个人讲话的声音都是有固定的频率范围,不同的人讲话的频率是不同的,FFT就专门...
  • 重复音乐查找助手是一个智能化的音乐文件对比工具,通过这个软件分析后,一切相似度高的音频文件都将被标记,让你海量的音乐文件中不存在重复的文件浪费空间,并节约听音乐时找音乐所需要的时间。 重复音乐查找...
  • [] 音频相似度计算 源语言: GoLang 文本相似度: 小文本采用的方式为php自带的文本比较即可: // 简单字符串匹配,适用于当长度小的情况 func SimpleCompareTextSimilarity(prev, newUpload string) (float64, ...
  • 计算文本相似度的常用算法

    千次阅读 2021-03-07 14:33:43
    NLP、数据挖掘领域中,文本分析是一个很重要的领域,这有助于我们去让...文本不仅仅是文字,文本相似度的应用更广,除了文字的匹配,还可以是图片、音频等,因为它们的实质都是在计算机中都是以二进制的方式存在的。相.
  • 大概估算音频中一段对话到另一端对话的时间间隔,将音频截取为不同对话的小音频文件,通过百度语音识别转换成英文,然后与原文对比。 2.先上结果图吧。大概的效果如图所示 timespan是每段对话的开始时间戳,...
  • 1.解释 1*feature_query.shape[0]矩阵与feature_query.shape[0]*m矩阵做矩阵的乘法,得到1*m的矩阵就是计算的...上图来自(余弦距离、欧氏距离和杰卡德相似性度量的对比分析) import torch distmat = torc...
  • 音频特征提取及差异

    万次阅读 2017-12-28 11:30:21
    * np.sqrt(2.0/n_input) librosa中提取mfcc很简单,读取音频文件后一行代码就可以完成,以下是mfcc函数内部 # -- Mel spectrogram and MFCCs -- # def mfcc(y=None, sr=22050, S=None, n_mfcc=20, **kwargs): """Mel...
  • 在图像、视频、文本、音频领域,做向量的相似性搜索,有很多应用点,比如:图像识别,语音识别、垃圾邮件过滤。 这种基于相似度检索的方案,不同于机器学习模型的方案。比如用有监督学习模型来做人脸识别,模型的可...
  • NLP——计算文本相似度的常用算法

    千次阅读 2020-07-03 16:12:51
    文章目录一、绪论二、余弦相似度2.1 余弦相似度定义2.2 计算相似度步骤2.3 举例2.4 改进方式2.5 代码三、TF-IDF计算3.1 TF、IDE、TF-IDF的计算方法3.1.1 词频TF的计算方法3.1.2 反文档频率IDF的计算方法3.1.3 TF-IDF...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 932
精华内容 372
关键字:

音频相似度对比