代码分析JAVA中PCM人声音频变声处理

项目中需要用到对PCM人声音频数据进行变声处理。苦苦挣扎了一周终于找到了纯Java实现的一套框架——TarsosDSP。功能非常强大!可以实时音频处理!当然我只用到了对文件处理。实际上逻辑是一样的

TarsosDSP的GitHub地址:https://github.com/JorenSix/TarsosDSP 将它整合至自己的项目工程。

具体Java工具类代码:

  /**
   * 变声
   * @param rawPcmInputStream 原始PCM数据输入流
   * @param speedFactor 变速率 (0,2) 大于1为加快语速,小于1为放慢语速
   * @param rateFactor 音调变化率 (0,2) 大于1为降低音调(深沉),小于1为提升音调(尖锐)
   * @return 变声后的PCM数据输入流
   */
  public static InputStream speechPitchShift(final InputStream rawPcmInputStream,double speedFactor,double rateFactor) {
    TarsosDSPAudioFormat format = new TarsosDSPAudioFormat(16000,16,1,true,false);
    AudioInputStream inputStream = new AudioInputStream(rawPcmInputStream, JVMAudioInputStream.toAudioFormat(format),AudioSystem.NOT_SPECIFIED);
    JVMAudioInputStream stream = new JVMAudioInputStream(inputStream);
    WaveformSimilarityBasedOverlapAdd w = new WaveformSimilarityBasedOverlapAdd(WaveformSimilarityBasedOverlapAdd.Parameters.speechDefaults(speedFactor, 16000));
    int inputBufferSize = w.getInputBufferSize();
    int overlap = w.getOverlap();
    AudioDispatcher dispatcher = new AudioDispatcher(stream, inputBufferSize ,overlap);
    w.setDispatcher(dispatcher);
    AudioOutputToByteArray out = new AudioOutputToByteArray();
    dispatcher.addAudioProcessor(w);
    dispatcher.addAudioProcessor(new RateTransposer(rateFactor));
    dispatcher.addAudioProcessor(out);
    dispatcher.run();
    return new ByteArrayInputStream(out.getData());
  }

其中数据转录器(AudioOutputToByteArray)代码如下:

public class AudioOutputToByteArray implements AudioProcessor {
  private boolean isDone = false;
  private byte[] out = null;
  private ByteArrayOutputStream bos;
  public AudioOutputToByteArray() {
    bos = new ByteArrayOutputStream();
  }
  public byte[] getData() {
    while (!isDone && out == null) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException ignored) {}
    }
    return out;
  }
  @Override
  public boolean process(AudioEvent audioEvent) {
    bos.write(audioEvent.getByteBuffer(),0,audioEvent.getByteBuffer().length);
    return true;
  }
  @Override
  public void processingFinished() {
    out = bos.toByteArray().clone();
    bos = null;
    isDone = true;
  }
}

可以通过这个工具方法播放音频:

  /**
   * 播放PCM
   *
   * 不要在非桌面环境调用。。。鬼知道会发生什么
   * @param rawPcmInputStream 原始PCM数据输入流
   * @throws LineUnavailableException
   */
  public static void play(final InputStream rawPcmInputStream) throws LineUnavailableException {
    TarsosDSPAudioFormat format = new TarsosDSPAudioFormat(16000,16,1,true,false);
    AudioInputStream inputStream = new AudioInputStream(rawPcmInputStream, JVMAudioInputStream.toAudioFormat(format),AudioSystem.NOT_SPECIFIED);
    JVMAudioInputStream stream = new JVMAudioInputStream(inputStream);
    AudioDispatcher dispatcher = new AudioDispatcher(stream, 1024 ,0);
    dispatcher.addAudioProcessor(new AudioPlayer(format,1024));
    dispatcher.run();
  }

您可能感兴趣的文章:

  • Java使用IO流实现音频的剪切和拼接
  • 实例解析使用Java实现基本的音频播放器的编写要点
  • java音频播放示例分享(java如何播放音频)
  • 使用javax.sound实现简单音频播放
(0)

相关推荐

  • 使用javax.sound实现简单音频播放

    本文实例为大家分享了javax.sound实现简单音频播放的具体代码,供大家参考,具体内容如下 /** * @see * @author Al_assad yulinying_1994@outlook.com * @date 2016年11月17日 下午6:27:59 * @version V1.0 * Description: 简易音频播放器(只支持AU,RA,WAV) * 在不使用JMF的情况下快速实现音频播放 * */ import javax.sound.sampled.*; impor

  • Java使用IO流实现音频的剪切和拼接

    需求: 使用IO流将指定目录下的若干个音频文件的高潮部分,进行剪切,并重新拼接成一首新的音频文件 思路(以两首歌为例): 第一首歌有一个输入流对象bis1.第二首歌有一个输入流对象bis2,他们公用一条输出流对象bos(在选择构造方法的时候选择含有布尔类型参数的那个),待第一首歌剪切完成后,在此基础上追加第二首歌的"高潮部分". 实现代码: import java.io.BufferedInputStream; import java.io.BufferedOutputStream;

  • 实例解析使用Java实现基本的音频播放器的编写要点

    Java音频播放,因为必须依赖到本地环境,所以JAVA在音频处理方面优势不大,或者说打从Java体系开发时就没太多的考虑音频播放因素,要知道最早的Java 1.1版本中,没有后来的javax.sound包,音频只能通过Applet包调取-- 遗憾的是,在图形程序开发中,我们的程序却又难免要使用到背景音乐.效果音等配合图像操作,哎,这实在是Sun大神给我们开的一个不打不小的玩笑.万幸后来Sun大神开眼,提供了javax.sound包,才解救我们于水深火热当中~ 但是继之而来的问题是,在javax.

  • java音频播放示例分享(java如何播放音频)

    这是一份精简后的代码,能够支持的格式十分有限. 复制代码 代码如下: package com.hongyuan.test; import java.io.File;import java.io.IOException; import javax.sound.sampled.AudioFormat;import javax.sound.sampled.AudioInputStream;import javax.sound.sampled.AudioSystem;import javax.sound

  • 代码分析JAVA中PCM人声音频变声处理

    项目中需要用到对PCM人声音频数据进行变声处理.苦苦挣扎了一周终于找到了纯Java实现的一套框架--TarsosDSP.功能非常强大!可以实时音频处理!当然我只用到了对文件处理.实际上逻辑是一样的 TarsosDSP的GitHub地址:https://github.com/JorenSix/TarsosDSP 将它整合至自己的项目工程. 具体Java工具类代码: /** * 变声 * @param rawPcmInputStream 原始PCM数据输入流 * @param speedFactor

  • 代码分析Java中线程的等待与唤醒

    我们先来看一下实例代码: class ThreadA extends Thread{ public ThreadA(String name) { super(name); } public void run() { synchronized (this) { System.out.println(Thread.currentThread().getName()+" call notify()"); notify(); } } } public class WaitTest { publ

  • 分析Java中为什么String不可变

    常量池 Java中我们创建String对象有两种基本方法. String str1 = "zxhtom"; String str2 = new String("zxhtom"); 上面两种方式我们创建了两个String变量 . 但是第一种通过双引号创建的zxhtom这个对象我们称之为常量 . 在JVM中是存储在一块叫[常量池]中的.而第二种str2是我们称之为普通变量.new一次就在JVM中开辟一块内存. [常量池]的作用就是复用,当同样的内容再次被通过常量方式创建

  • 分析Java中Map的遍历性能问题

    一.引言 我们知道java HashMap的扩容是有成本的,为了减少扩容的次数和成本,可以给HashMap设置初始容量大小,如下所示: HashMap<string, integer=""> map0 = new HashMap<string, integer="">(100000); 但是在实际使用的过程中,发现性能不但没有提升,反而显著下降了!代码里对HashMap的操作也只有遍历了,看来是遍历出了问题,于是做了一番测试,得到如下结果:

  • 分析java 中AspectJ切面执行两次的原因

    分析java 中AspectJ切面执行两次的原因 背景 转眼之间,发现博客已经将近半年没更新了,甚是惭愧.话不多说,正如标题所言,最近在使用AspectJ的时候,发现拦截器(AOP切面)执行了两次了.我们知道,AspectJ是AOP的一种解决方案,本质上是通过代理类在目标方法执行通知(Advice),然后由代理类再去调用目标方法.所以,从这点讲,拦截器应该只会执行一次.但是在测试的时候发现拦截器执行了两次. 问题重现 既然问题已经明了,那么可以通过代码简单重现这个问题,从而更深层次分析到底是什么

  • 分析java中全面的单例模式多种实现方式

    一.单例模式的思想 想整理一些 java 并发相关的知识,不知道从哪开始,想起了单例模式中要考虑的线程安全,就从单例模式开始吧.以前写过单例模式,这里再重新汇总补充整理一下,单例模式的多种实现. 单例模式的主要思想是: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象 这种说法看上去没错,但也好像不太准确.其实,就算外界能随意 new 出新的实例对象,但只要我们保证

  • 分析Java中的类加载问题

    目录 一.Java类的加载顺序 二.类加载过程 三.被动引用中和类静态初始化的关系 四.类加载器双亲委派 一.Java类的加载顺序 引用1个网上的经典例子,并做稍许改动,以便大家更好地理解. public class Animal { private int i = test(); private static int j = method(); static { System.out.println("a"); } Animal(){ System.out.println("

  • 实例分析java中重载与重写的区别

    本文以实例详细分析了Java中重载与重写的区别,感兴趣的朋友可以参考一下. 一.重载(Overloading): (1) 方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型. 重载Overloading是一个类中多态性的一种表现. (2)Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义. 调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性. (3) 重载的时候,方

  • 代码分析c++中string类

    一:回顾 (1)c++中的string类是在面试中和笔试中经常考的题目: 工程代码免费下载 string类的自行实现 (2)c++中的string类和fstream类合起来是处理外部数据的利器: (3)string类经常用到find find_first_of find_first_not_of find_last_of find_last_not_of substr replace等,以及联合使用来达到java中的split和trim (4) 使用friend 仅仅是在类中进行声明的非内部 却

  • 实例分析Java中public static void main(String args[])是什么意思

    本文实例讲述了Java中public static void main(String args[])的来龙去脉.分享给大家供大家参考,具体如下: public static void main(String[] args) 这绝对不是凭空想出来的,也不是没有道理的死规定,而是java程序执行的需要. jvm在试图运行一个类之前,先检查该类是否包含一个特殊方法.这个方法必须是公有的,以便在任何位置都能访问得到.这个方法必须是static的,因为这个方法不能依赖任何该类的实例即可运行,而非stati

随机推荐