java实现变声器--变声萝莉

news/2025/1/1 12:17:07/

编写java变声器需要做的前期准备

安装 ffmgeg 下载地址 Releases · BtbN/FFmpeg-Builds · GitHub

win系统下载 ffmpeg-N-103272-g7bba0dd638-win64-gpl.zip

配置环境变量到 bin目录 

 新建maven程序加入两个引用

<!-- https://mvnrepository.com/artifact/com.github.st-h/TarsosDSP --><dependency><groupId>com.github.st-h</groupId><artifactId>TarsosDSP</artifactId><version>2.4.1</version></dependency><dependency><groupId>ws.schild</groupId><artifactId>jave-core</artifactId><version>2.4.6</version></dependency>

新建两个基础类

AudioOutputToByteArray

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

WaveHeader

import java.io.ByteArrayOutputStream;
import java.io.IOException;public class WaveHeader {public final char fileID[] = {'R', 'I', 'F', 'F'};public int fileLength;public char wavTag[] = {'W', 'A', 'V', 'E'};;public char FmtHdrID[] = {'f', 'm', 't', ' '};public int FmtHdrLeth;public short FormatTag;public short Channels;public int SamplesPerSec;public int AvgBytesPerSec;public short BlockAlign;public short BitsPerSample;public char DataHdrID[] = {'d','a','t','a'};public int DataHdrLeth;public byte[] getHeader() throws IOException {ByteArrayOutputStream bos = new ByteArrayOutputStream();WriteChar(bos, fileID);WriteInt(bos, fileLength);WriteChar(bos, wavTag);WriteChar(bos, FmtHdrID);WriteInt(bos,FmtHdrLeth);WriteShort(bos,FormatTag);WriteShort(bos,Channels);WriteInt(bos,SamplesPerSec);WriteInt(bos,AvgBytesPerSec);WriteShort(bos,BlockAlign);WriteShort(bos,BitsPerSample);WriteChar(bos,DataHdrID);WriteInt(bos,DataHdrLeth);bos.flush();byte[] r = bos.toByteArray();bos.close();return r;}private void WriteShort(ByteArrayOutputStream bos, int s) throws IOException {byte[] mybyte = new byte[2];mybyte[1] =(byte)( (s << 16) >> 24 );mybyte[0] =(byte)( (s << 24) >> 24 );bos.write(mybyte);}private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {byte[] buf = new byte[4];buf[3] =(byte)( n >> 24 );buf[2] =(byte)( (n << 8) >> 24 );buf[1] =(byte)( (n << 16) >> 24 );buf[0] =(byte)( (n << 24) >> 24 );bos.write(buf);}private void WriteChar(ByteArrayOutputStream bos, char[] id) {for (int i=0; i<id.length; i++) {char c = id[i];bos.write(c);}}
}

现在新建执行类和方法,先在d盘放一个1.mp3的文件。以下代码就是把1.mp3转换成变声后的2.mp3

byte[] pcmBytes = speechPitchShiftMp3("d://1.mp3", 0.73, 0.73); 后面的0.73就是变声参数。最后会给出各种变声参数

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;import javax.sound.sampled.UnsupportedAudioFileException;import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.WaveformSimilarityBasedOverlapAdd;
import be.tarsos.dsp.effects.DelayEffect;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.resample.RateTransposer;public class ceshi {public static void main(String[] args) throws Exception {//这里返回的是pcm格式的音频byte[] pcmBytes = speechPitchShiftMp3("d://1.mp3", 0.73, 0.73);//如果需要转成wav则需要给pcmBytes增加一个头部信息//TarsosDSP中也有输出Wav格式音频的处理器,这里没有使用。byte[] wavHeader = pcm2wav(pcmBytes);OutputStream wavOutPut = new FileOutputStream("d://2.mp3");wavOutPut.write(wavHeader);wavOutPut.write(pcmBytes);wavOutPut.flush();wavOutPut.close();// 对于各种声音类型,以及所需添加的处理器,还有处理器参数代码,将在本文最后给出。//如果需要转mp3格式的,也可以给我留言,我会加上。}/*** 变声* @param speedFactor 变速率 (0,2) 大于1为加快语速,小于1为放慢语速* @param rateFactor 音调变化率 (0,2) 大于1为降低音调(深沉),小于1为提升音调(尖锐)* @return 变声后的MP3数据输入流*/public static byte[] speechPitchShiftMp3(String fileUrl, double rateFactor, double speedFactor) throws IOException, UnsupportedAudioFileException {WaveformSimilarityBasedOverlapAdd w = new WaveformSimilarityBasedOverlapAdd(WaveformSimilarityBasedOverlapAdd.Parameters.speechDefaults(rateFactor, 16000));int inputBufferSize = w.getInputBufferSize();int overlap = w.getOverlap();AudioDispatcher dispatcher = AudioDispatcherFactory.fromPipe(fileUrl,16000,inputBufferSize,overlap);w.setDispatcher(dispatcher);dispatcher.addAudioProcessor(w);/** 采样率转换器。 使用插值更改采样率, 与时间拉伸器一起可用于音高转换。 **/dispatcher.addAudioProcessor(new RateTransposer(speedFactor));AudioOutputToByteArray out = new AudioOutputToByteArray();/** 声音速率转换器 -- 失败 **//*SoundTouchRateTransposer soundTouchRateTransposer = new SoundTouchRateTransposer(2);soundTouchRateTransposer.setDispatcher(dispatcher);dispatcher.addAudioProcessor(soundTouchRateTransposer);*//** 正弦波发生器 -- 无反应 **//*SineGenerator sineGenerator = new SineGenerator(0.5, 0.5);dispatcher.addAudioProcessor(sineGenerator);*//** 音调转换器 -- 无效果 **/
//	        dispatcher.addAudioProcessor(new PitchShifter(0.1,16000,448,overlap));/** 制粒机使用颗粒合成回放样本。方法可用于控制播放速率,音高,颗粒大小, -- 无效果 **/
//	        dispatcher.addAudioProcessor(new OptimizedGranulator(16000, 448));/** 噪音产生器 -- 有效果 **/
//	        dispatcher.addAudioProcessor(new NoiseGenerator(0.2   ));/** 增益处理器  增益为1,则无任何反应。 增益大于1表示音量增加a -- 有反应 **/
//	        dispatcher.addAudioProcessor(new GainProcessor(10));/**镶边效果 -- 有反应 **/
//	        dispatcher.addAudioProcessor(new FlangerEffect(64, 0.3, 16000, 16000));// 回声效果
//	        dispatcher.addAudioProcessor(new FlangerEffect(1 << 4, 0.8, 8000, 2000));// 感冒
//	        dispatcher.addAudioProcessor(new ZeroCrossingRateProcessor());//感冒/** 淡出 --声音慢慢变小 **/
//	        dispatcher.addAudioProcessor(new FadeOut(5));/** 淡入-- 声音慢慢变大 **/
//	        dispatcher.addAudioProcessor(new FadeIn(5));/** 在信号上添加回声效果。echoLength以秒为单位  elay回声的衰减,介于0到1之间的值。1表示无衰减,0表示立即衰减 **/dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000) );/** 调幅噪声 -- 将声音转换为噪声**/
//	        dispatcher.addAudioProcessor(new AmplitudeModulatedNoise());/** 振幅LFO -- 声音波动 **/
//	        dispatcher.addAudioProcessor(new AmplitudeLFO());dispatcher.addAudioProcessor(out);dispatcher.run();//	        return new ByteArrayInputStream(out.getData());return out.getData();}public static byte[] pcm2wav(byte[] bytes) throws IOException {//填入参数,比特率等等。这里用的是16位单声道 8000 hzWaveHeader header = new WaveHeader();//长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)header.fileLength = bytes.length + (44 - 8);header.FmtHdrLeth = 16;header.BitsPerSample = 16;header.Channels = 1;header.FormatTag = 0x0001;header.SamplesPerSec = 16000;header.BlockAlign = (short)(header.Channels * header.BitsPerSample / 8);header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;header.DataHdrLeth = bytes.length;byte[] h = header.getHeader();assert h.length == 44; //WAV标准,头部应该是44字节return h;}}

 各种参数类

LUOLI(0.6, 0.6, "萝莉", 1, dispatcher -> {})

byte[] pcmBytes = speechPitchShiftMp3("d://1.mp3", 0.73, 0.73);改为

byte[] pcmBytes = speechPitchShiftMp3("d://1.mp3", 0.6, 0.6);就可以了

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.WaveformSimilarityBasedOverlapAdd;
import be.tarsos.dsp.ZeroCrossingRateProcessor;
import be.tarsos.dsp.effects.DelayEffect;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.resample.RateTransposer;import java.io.File;
import java.io.IOException;
import java.util.Optional;
import java.util.function.Consumer;public enum SoundEnum {LUOLI(0.6, 0.6, "萝莉", 1, dispatcher -> {}),DASHU(1.2, 1.2, "大叔", 2, dispatcher -> {}),FEIZAI(1.5, 1.5, "肥仔", 3, dispatcher -> {}),GAOGUAI(1.5, 0.8, "搞怪", 4, dispatcher -> {}),XIONGHAIZI(0.73, 0.73, "熊孩子", 5, dispatcher -> {}),MANTUNTUN(0.35,1, "慢吞吞",6 , dispatcher -> {}),WANGHONGNV(1.2,0.7, "网红女",7 , dispatcher -> {}),/*** dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000) );*/KUNSHOU(1.55,1.55, "困兽", 8, dispatcher -> dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000))),/*** dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000) );*/ZHONGJIXIE(1.50,1.50, "重机械", 9, dispatcher -> dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000))),/***          dispatcher.addAudioProcessor(new FlangerEffect(1 << 4, 0.8, 8000, 2000));*         dispatcher.addAudioProcessor(new ZeroCrossingRateProcessor());*/GANMAO(1.05,1.05, "感冒", 10, dispatcher -> {dispatcher.addAudioProcessor(new DelayEffect(0.2, 0.24, 12000));dispatcher.addAudioProcessor(new ZeroCrossingRateProcessor());}),/***          dispatcher.addAudioProcessor(new DelayEffect(0.8, 0.5, 12000) );*         dispatcher.addAudioProcessor(new DelayEffect(0.5, 0.3, 8000) );*/KONGLING(1, 1, "空灵", 11, dispatcher -> {dispatcher.addAudioProcessor(new DelayEffect(0.8, 0.5, 12000) );dispatcher.addAudioProcessor(new DelayEffect(0.5, 0.3, 8000) );});/*** @param speedFactor 变速率 (0,2) 大于1为加快语速,小于1为放慢语速* @param rateFactor 音调变化率 (0,2) 大于1为降低音调(深沉),小于1为提升音调(尖锐)*/SoundEnum(double rateFactor, double speedFactor, String name, int type, Consumer<AudioDispatcher> consumer){this.rateFactor = rateFactor;this.speedFactor = speedFactor;this.name = name;this.type = type;this.consumer = consumer;}private double rateFactor;private double speedFactor;private String name;private int type;private Consumer consumer;public byte[] run(String fileUrl){WaveformSimilarityBasedOverlapAdd w = new WaveformSimilarityBasedOverlapAdd(WaveformSimilarityBasedOverlapAdd.Parameters.speechDefaults(rateFactor, 16000));int inputBufferSize = w.getInputBufferSize();int overlap = w.getOverlap();AudioDispatcher dispatcher = AudioDispatcherFactory.fromPipe(fileUrl,16000,inputBufferSize,overlap);w.setDispatcher(dispatcher);dispatcher.addAudioProcessor(w);/** 采样率转换器。 使用插值更改采样率, 与时间拉伸器一起可用于音高转换。 **/dispatcher.addAudioProcessor(new RateTransposer(speedFactor));AudioOutputToByteArray out = new AudioOutputToByteArray();consumer.accept(dispatcher);dispatcher.addAudioProcessor(out);dispatcher.run();return out.getData();}public static byte[] pcm2wav(byte[] bytes) {try {//填入参数,比特率等等。这里用的是16位单声道 8000 hzWaveHeader header = new WaveHeader();//长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)header.fileLength = bytes.length + (44 - 8);header.FmtHdrLeth = 16;header.BitsPerSample = 16;header.Channels = 1;header.FormatTag = 0x0001;header.SamplesPerSec = 16000;header.BlockAlign = (short)(header.Channels * header.BitsPerSample / 8);header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;header.DataHdrLeth = bytes.length;byte[] h = header.getHeader();assert h.length == 44; //WAV标准,头部应该是44字节return h;} catch (IOException e) {//log.error("pcm2wav-error", e);}return null;}public static Optional<SoundEnum> getInstance(int type){for (int i = 0; i < SoundEnum.values().length; i++) {if(SoundEnum.values()[i].type == type)return Optional.of(SoundEnum.values()[i]);}return Optional.empty();}
}


http://www.ppmy.cn/news/544974.html

相关文章

matlab调制变声,MATLAB变声程序代码

% ct1 clear all,close all, clc; % 定义常数 FL 80; % 帧长 WL 240; % 窗长 P 10; % 预测系数个数 [s,fs] wavread(sunday_2.wav); % 载入语音s s s/max(s); %归一化 L length(s); % 读入语音长度 FN floor(L/FL)-2; % 计算帧数 % 预测和重建滤波器 exc zeros(L,1); %…

Android 端音频变声方案

音频变声实质上是通过调整 PCM 数据的音调、节拍等属性&#xff0c;实现听感上的变化。如果是 mp3、aac 等压缩音频&#xff0c;则需提前解码成 PCM 数据&#xff0c;Android 端可以通过 MediaExtractor 及 MediaCodec 解码得到 PCM&#xff0c;但调整音调、节拍仅靠 Android a…

实时语音变声技术原理解析:“大叔变小萝莉”

游戏社交化是近年来游戏行业发展的重要趋势&#xff0c;如何提高游戏的社交属性已成为各大游戏厂商游戏策划的重要组成部分。游戏中玩家的互动形式也不再止于语音聊天&#xff0c;有了更为高阶的需求&#xff0c;比如&#xff1a;玩家在“吃鸡”的时候&#xff0c;会通过外带的…

MATLAB变声器程序

clear;clc; [s,fs,] audioread(‘61.m4a’); % 载入语音s s(1:3000)s(1:3000)randn(3000,1)*eps; s s/max(s); %归一化 L length(s); % 读入语音长度 figure(1); subplot(211);plot(s);title(‘原始语音信号波形’) subplot(212);plot(abs(s));title(‘原始语音信号频谱’) …

光变声

为何变&#xff1f; 今年智能车竞赛中的信标组的导引信号发生了改变&#xff0c;由原来的光&#xff0c;变成了声&#xff08;还有射频信号&#xff09;&#xff0c;除了传承智能车竞赛赛题永远在变化的传统&#xff0c;还有阻断…&#xff08;此处省略三千字&#xff09;。 …

语音模块:pyttsx变声项目

目录 一、说明 二、安装 三、基本用法 四、结论 一、说明 程序员们好&#xff0c;我们将在本教程中看到如何使用 Python 中的 pyttsx3 将语音转换为文本。也可以将人的语音实现变音、变速等处理。 pyttsx3 库是 Python 中的文本到语音转换库。该库离线工作&#xff0c;使其…

怎样将音频变声?三分钟教会你

音频变声是一种常见的音频处理方式&#xff0c;可以对人声或音乐进行特殊处理&#xff0c;使其声音产生不同的效果。它的应用广泛&#xff0c;像是音乐制作人可能需要使用音频变声来改变歌手的声音&#xff0c;使其更加独特或与歌曲的风格相匹配。例如&#xff0c;将男歌手的声…

人声变声器的原理

班级&#xff1a;自 02    姓名&#xff1a;石湛   学号&#xff1a;2020011069院系&#xff1a;自动化系 指导老师&#xff1a;卓晴  简 介&#xff1a; 声音作为一种由振动而产生的机械波&#xff0c;本身就是一个连续的时间信号。我们对声音的处理将会充分运用信号与…