Java实现Shazam声音识别算法的实例代码

 更新时间:2018年09月10日 10:32:13   作者:llhhzz1989  
Shazam算法采用傅里叶变换将时域信号转换为频域信号,并获得音频指纹,最后匹配指纹契合度来识别音频。这篇文章给大家介绍Java实现Shazam声音识别算法的实例代码,需要的朋友参考下吧

Shazam算法采用傅里叶变换将时域信号转换为频域信号,并获得音频指纹,最后匹配指纹契合度来识别音频。

1、AudioSystem获取音频

奈奎斯特-香农采样定理告诉我们,为了能捕获人类能听到的声音频率,我们的采样速率必须是人类听觉范围的两倍。人类能听到的声音频率范围大约在20Hz到20000Hz之间,所以在录制音频的时候采样率大多是44100Hz。这是大多数标准MPEG-1 的采样率。44100这个值最初来源于索尼,因为它可以允许音频在修改过的视频设备上以25帧(PAL)或者30帧( NTSC)每秒进行录制,而且也覆盖了专业录音设备的20000Hz带宽。所以当你在选择录音的频率时,选择44100Hz就好了。

定义音频格式:

  public static float sampleRate = 44100;
  public static int sampleSizeInBits = 16;
  public static int channels = 2; // double
  public static boolean signed = true; // Indicates whether the data is signed or unsigned
  public static boolean bigEndian = true; // Indicates whether the audio data is stored in big-endian or little-endian order
  public AudioFormat getFormat() {
    return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
        bigEndian);
  }

调用麦克风获取音频,保存到out中

 public static ByteArrayOutputStream out = new ByteArrayOutputStream();1
    try {
      AudioFormat format = smartAuto.getFormat(); // Fill AudioFormat with the settings
      DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
      startTime = new Date().getTime();
      System.out.println(startTime);
      SmartAuto.line = (TargetDataLine) AudioSystem.getLine(info);
      SmartAuto.line.open(format);
      SmartAuto.line.start();
      new FileAnalysis().getDataToOut("");
      while (smartAuto.running) {
        checkTime(startTime);
      }
      SmartAuto.line.stop();
      SmartAuto.line.close();
    } catch (Throwable e) {
      e.printStackTrace();
    }

获取到的out数据需要通过傅里叶变换,从时域信号转换为频域信号。

傅里叶变换

public Complex[] fft(Complex[] x) {
    int n = x.length;
    // 因为exp(-2i*n*PI)=1,n=1时递归原点
    if (n == 1){
      return x;
    }
    // 如果信号数为奇数,使用dft计算
    if (n % 2 != 0) {
      return dft(x);
    }
    // 提取下标为偶数的原始信号值进行递归fft计算
    Complex[] even = new Complex[n / 2];
    for (int k = 0; k < n / 2; k++) {
      even[k] = x[2 * k];
    }
    Complex[] evenValue = fft(even);
    // 提取下标为奇数的原始信号值进行fft计算
    // 节约内存
    Complex[] odd = even;
    for (int k = 0; k < n / 2; k++) {
      odd[k] = x[2 * k + 1];
    }
    Complex[] oddValue = fft(odd);
    // 偶数+奇数
    Complex[] result = new Complex[n];
    for (int k = 0; k < n / 2; k++) {
      // 使用欧拉公式e^(-i*2pi*k/N) = cos(-2pi*k/N) + i*sin(-2pi*k/N)
      double p = -2 * k * Math.PI / n;
      Complex m = new Complex(Math.cos(p), Math.sin(p));
      result[k] = evenValue[k].add(m.multiply(oddValue[k]));
      // exp(-2*(k+n/2)*PI/n) 相当于 -exp(-2*k*PI/n),其中exp(-n*PI)=-1(欧拉公式);
      result[k + n / 2] = evenValue[k].subtract(m.multiply(oddValue[k]));
    }
    return result;
  }

计算out的频域值

 private void setFFTResult(){
    byte audio[] = SmartAuto.out.toByteArray();
    final int totalSize = audio.length;
    System.out.println("totalSize = " + totalSize);
    int chenkSize = 4;
    int amountPossible = totalSize/chenkSize;
    //When turning into frequency domain we'll need complex numbers: 
    SmartAuto.results = new Complex[amountPossible][];
    DftOperate dfaOperate = new DftOperate();
    //For all the chunks: 
    for(int times = 0;times < amountPossible; times++) {
      Complex[] complex = new Complex[chenkSize];
      for(int i = 0;i < chenkSize;i++) {
        //Put the time domain data into a complex number with imaginary part as 0: 
        complex[i] = new Complex(audio[(times*chenkSize)+i], 0);
      }
      //Perform FFT analysis on the chunk: 
      SmartAuto.results[times] = dfaOperate.fft(complex);
    }
    System.out.println("results = " + SmartAuto.results.toString());
  }

总结

以上所述是小编给大家介绍的Java实现Shazam声音识别算法的实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • Java的NIO之并发环境下非阻塞IO技术详解

    Java的NIO之并发环境下非阻塞IO技术详解

    这篇文章主要介绍了Java的NIO之并发环境下非阻塞IO技术详解,Java NIO(New IO)是Java平台提供的一种用于高效处理I/O操作的API,它引入了一组新的类和概念,以提供更好的性能和可扩展性,需要的朋友可以参考下
    2023-09-09
  • 深入剖析springBoot中的@Scheduled执行原理

    深入剖析springBoot中的@Scheduled执行原理

    这篇文章主要介绍了springBoot中的@Scheduled执行原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java集合之整体结构

    Java集合之整体结构

    Java中集合类是Java编程中使用最频繁、最方便的类。接下来通过本文给大家介绍Java集合之整体结构,一起看看吧
    2016-05-05
  • Java中的Monad设计模式及其实现过程

    Java中的Monad设计模式及其实现过程

    本文介绍了Java中的Monad设计模式及其在函数式编程中的应用,虽然Java不是函数式编程语言,但可以通过接口和泛型模拟Monad的行为,实现链式调用和上下文管理,通过一个示例展示了如何使用OptionalMonad进行链式调用,并解析了Monad接口和OptionalMonad的实现细节
    2025-03-03
  • 解决bootstrap.yml不生效,无法优先于application.yml文件加载问题

    解决bootstrap.yml不生效,无法优先于application.yml文件加载问题

    文章主要讨论了在Spring Boot项目中,`bootstrap.yml`文件无法优先于`application.yml`文件加载的问题,原因是缺少了`nacos-config`依赖,且需要确保Spring Boot版本与`nacos-config`版本匹配,作者希望通过分享个人经验,帮助他人解决类似问题
    2024-12-12
  • MyBatis通用Mapper实现原理及相关内容

    MyBatis通用Mapper实现原理及相关内容

    今天小编就为大家分享一篇关于MyBatis通用Mapper实现原理及相关内容,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • java题解Leetcode 8字符串转换整数

    java题解Leetcode 8字符串转换整数

    这篇文章主要为大家介绍了java题解Leetcode 8字符串转换整数实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Java定义画板类的方法

    Java定义画板类的方法

    这篇文章主要为大家详细介绍了Java定义画板类的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • SpringCloud全面解析@FeignClient标识接口的过程

    SpringCloud全面解析@FeignClient标识接口的过程

    这篇文章主要介绍了SpringCloud全面解析@FeignClient标识接口的过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Springboot SseEmitter流式输出的实现代码

    Springboot SseEmitter流式输出的实现代码

    本文介绍了Spring Boot中使用SseEmitter实现流式输出的原理和示例代码,通过SseEmitter,可以实现客户端和服务器之间的实时通信,服务器可以分块发送数据,而客户端可以实时接收和处理这些数据,,感兴趣的朋友一起看看吧
    2025-03-03

最新评论