使用以下 java 中的代码修改文件中特定位置的音频文件的音高
Posted
技术标签:
【中文标题】使用以下 java 中的代码修改文件中特定位置的音频文件的音高【英文标题】:To modify the pitch of an audio file at specific positions in the files using the codes in java below 【发布时间】:2015-03-18 06:20:57 【问题描述】:我想根据用户在不同时刻的输入动态修改音频剪辑的音高,比如如果用户输入在 10 秒后改变音频的音高,那么我该如何实现呢?
我发现这个link 描述了如何修改音高,但我想在音频剪辑的不同时刻重复这个过程,并且只持续一段时间。有人可以指导我吗?
一些修改
编辑 1
我发现了这段代码,正如我之前提到的那样
//source file
final File file1 = new File(“Sample.mp3”);
//destination file
final File file2 = new File(“Sample_cat.wav”);
//audio stream of file1
final AudioInputStream in1 = getAudioInputStream(file1);
//get audio format for targetted sound
final AudioFormat inFormat = getOutFormat(in1.getFormat());
//change the frequency of Audio format
private AudioFormat getOutFormat(AudioFormat inFormat)
int ch = inFormat.getChannels();
float rate = inFormat.getSampleRate();
return new AudioFormat(PCM_SIGNED, 72000, 16, ch, ch * 2, rate,
inFormat.isBigEndian());
//get the target file audio stream using file format
final AudioInputStream in2 = getAudioInputStream(inFormat, in1);
//write the audio file in targeted pitch file
Audiosystem.write(in2, AudioFileFormat.Type.WAVE, file2);
编辑 2 我找到了另一个代码,它设置了您想要开始和停止音频的音频文件的位置。
File audioFile = new File(audioFilePath);
AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
AudioFormat format = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.open(audioStream);
audioClip.setLoopPoints(10_000, 500_000);
audioClip.loop(1);
现在,如何使用 Edit 1
中的代码更改 Edit 2 中设置的持续时间的音高,即 10 毫秒至 50 毫秒如果我可以用除 Java 之外的任何其他方式做同样的事情,有人可以建议我吗?那么欢迎提出建议... 请帮忙。我是新来的。
**编辑 3 **
可以参考这个链接上的确切问题:link
这些是我所指的值(以毫秒为单位):
public static void convertMsgToAudio(String msg)
int len = msg.length();
duration = new double[len];
msg = msg.toUpperCase();
System.out.println("Msg 2 : " + msg);
int i;
//char ch;
for(i=0;i<msg.length();i++)
if(msg.charAt(i) == 'A')
duration[i] = 50000;
else if (msg.charAt(i) == 'B')
duration[i] = 100000;
else if (msg.charAt(i) == 'C')
duration[i] = 150000;
else if (msg.charAt(i) == 'D')
duration[i] = 200000;
else if (msg.charAt(i) == 'E')
duration[i] = 250000;
else if (msg.charAt(i) == 'F')
duration[i] = 300000;
else if (msg.charAt(i) == 'G')
duration[i] = 350000;
else if (msg.charAt(i) == 'H')
duration[i] = 400000;
else if (msg.charAt(i) == 'I')
duration[i] = 450000;
else if (msg.charAt(i) == 'J')
duration[i] = 500000;
else if (msg.charAt(i) == 'K')
duration[i] = 550000;
else if (msg.charAt(i) == 'L')
duration[i] = 600000;
else if (msg.charAt(i) == 'M')
duration[i] = 650000;
else if (msg.charAt(i) == 'N')
duration[i] = 700000;
else if (msg.charAt(i) == 'O')
duration[i] = 750000;
else if (msg.charAt(i) == 'P')
duration[i] = 800000;
else if (msg.charAt(i) == 'Q')
duration[i] = 850000;
else if (msg.charAt(i) == 'R')
duration[i] = 900000;
else if (msg.charAt(i) == 'S')
duration[i] = 950000;
else if (msg.charAt(i) == 'T')
duration[i] = 1000000;
else if (msg.charAt(i) == 'U')
duration[i] = 1100000;
else if (msg.charAt(i) == 'V')
duration[i] = 1200000;
else if (msg.charAt(i) == 'W')
duration[i] = 1300000;
else if (msg.charAt(i) == 'X')
duration[i] = 1400000;
else if (msg.charAt(i) == 'Y')
duration[i] = 1500000;
else if (msg.charAt(i) == 'Z')
duration[i] = 1600000;
【问题讨论】:
没人能帮我吗? 如果我可以用除 Java 之外的任何其他方式做同样的事情,谁能建议我?那么欢迎提出建议... 【参考方案1】:据我所知,Java 不会公开 Clip 中的数据进行编辑。
我从未尝试过通过扰乱采样率来改变音高。也许这是一个很好的方法。 Java 教程中有一节介绍了 wav 文件格式的更改:Using Files and Format Converters。看起来这将是很好的背景信息,甚至可能涵盖您正在尝试的解决方案。
这就是我所做的,称之为 VarispeedWavPlayer。
(1) 有一个 volatile 实例浮点变量,它是一个速度因子(1 是相同速度,1.1 是 110%,0.5 是半速,等等。
(2) 有一个浮点数,它将是一个正在运行的“磁带头”
(3) 从从 AudioInputStream 读取并输出到 SourceDataLine 的普通代码开始(上述 Java 教程链接中“读取声音文件”中的好示例。
(4)在有评论的地方
// Here, do something useful with the audio data that's
// now in the audioBytes array...
(a) 将输入字节转换为 PCM 数据。
如何做到这一点的示例,使用 16 位编码、立体声、little-endian(“CD 质量”)。这使用大小为 1024 字节的读取缓冲区,它转换为 256 帧(记住,有两个轨道,左右)的短数据,范围从 -32767 到 32767(或者可能是 32768,我不记得那个细节了瞬间)。
while((bytesRead = audioInputStream.read(rawByteBuffer, 0, 1024)) != -1)
for (int i = 0, n = bytesRead / 2); i < n; i ++)
pcmBuffer[i] = ( rawByteBuffer[i * 2] & 0xff )
| ( rawByteBuffer[(i * 2) + 1)] << 8 ) ;
以上内容被编辑清楚,并且可以使用一些性能优化。
(b) 获取当前的“速度因子”并编写一个循环遍历 PCM 帧值(请记住,对于立体声,该轨道的“下一个”帧是 +2):
tapehead += speedfactor;
(c) 这通常会落在一个小数值上。使用线性插值计算该中间点的值。例如,如果您降落在磁带头 = 10.25,第 10 帧为 0.5,第 11 帧为 0.6,您将返回 0.525。
(d) 将插值转换回字节(步骤 4a 的逆向)
(e) 累积字节并通过 SourceDataLine 将它们发送出去。
在管理输入和输出字节缓冲区不会一对一匹配这一事实方面,我遗漏了一些细节。但是如果你掌握了基本概念,那么我认为你将能够解决这个问题。
注意,这只会在查询“speedFactor”变量时更新速度,每个输入缓冲区一次。所以你不希望输入缓冲区过大。
【讨论】:
感谢您的回复 :) 但我对音频没有很好的掌握.. 特别是我不明白如何将传入的数据转换为 PCM 数据.. 和后记......所以如果你能提供给我这个代码而不是伪代码,那将是一个很大的帮助......因为我的时间不多了,我不太擅长java ..但别无选择.. *** 已经解决了每个步骤。我认为,如果您搜索它们,您将获得一些成功。我的时间也很短。可能您的准备工作比您准备的要多一些,因为这确实需要的不仅仅是 Java 编码初学者的技能水平。 感谢您的建议,我会在这方面做一些事情......你能告诉我一件事吗......我已经在***.com/questions/29138169/… 上说明了确切的问题......你能告诉我是否您所说的方式将帮助我实现这一目标..?在此先感谢:) 取两个字节(假设 16 位编码,little-endian)并转换为从 -32767 到 32767 的 PCM,试试这行代码: int audioVal = ( buffer[i+1]以上是关于使用以下 java 中的代码修改文件中特定位置的音频文件的音高的主要内容,如果未能解决你的问题,请参考以下文章