我曾尝试将4个单独的字节数组合并到一个文件中,但我只得到空指针异常,我不知道为什么。我的音频格式是16位PCM签名的,我知道我应该使用short而不是bytes,但老实说,我完全迷茫了。
private short[] mixByteBuffers(byte[] bufferA, byte[] bufferB) {
short[] first_array = new short[bufferA.length/2];
short[] second_array = new short [bufferB.length/2];
short[] final_array = null;
if(first_array.length > second_array.length) {
short[] temp_array = new short[bufferA.length];
for (int i = 0; i < temp_array.length; i++) {
int mixed=(int)first_array[i] + (int)second_array[i];
if (mixed>32767) mixed=32767;
if (mixed<-32768) mixed=-32768;
temp_array[i] = (short)mixed;
final_array = temp_array;
}
}
else {
short[] temp_array = new short[bufferB.length];
for (int i = 0; i < temp_array.length; i++) {
int mixed=(int)first_array[i] + (int)second_array[i];
if (mixed>32767) mixed=32767;
if (mixed<-32768) mixed=-32768;
temp_array[i] = (short)mixed;
final_array = temp_array;
}
}
return final_array;
}
这就是我目前正在尝试的,但它正在以java返回。lang.ArrayIndexOutOfBoundsException:0
int mixed = (int)first_array[i] + (int)second_array[i];
我的数组长度不尽相同,我是这样调用函数的:
public void combineAudio() {
short[] combinationOne = mixByteBuffers(tempByteArray1, tempByteArray2);
short[] combinationTwo = mixByteBuffers(tempByteArray3, tempByteArray4);
short[] channelsCombinedAll = mixShortBuffers(combinationOne, combinationTwo);
byte[] bytesCombined = new byte[channelsCombinedAll.length * 2];
ByteBuffer.wrap(bytesCombined).order(ByteOrder.LITTLE_ENDIAN)
.asShortBuffer().put(channelsCombinedAll);
mixedByteArray = bytesCombined;
}
一定有比我现在做的更好的方法,这让我疯狂。
temp_数组。
循环的
else
子句中的length
值为bufferB。长度
。但是if
子句中的值是bufferA。长度/2
。在else
子句中,你是否忽略了除以2?
无论如何,通常只是将音频数据(信号)处理为流。打开每一行后,从每一行中获取一个预定义的缓冲区值,足以从每一行中获得相同数量的PCM值。如果一行在其他行之前用完,您可以用0值填充该行。
除非有非常充分的理由添加长度不等的数组,否则我认为最好避免这样做。相反,使用指针(如果你是从数组中绘制)或渐进read()方法(如果是从AudioInput行)来获得每次循环迭代的固定数量的PCM值。否则,我认为你是在自找麻烦,不必要地使事情复杂化。
我见过一些可行的解决方案,每次只从每个来源处理一个PCM值,甚至更多,比如1000甚至半秒(如果是44100 fps,则为22050)。主要的是在每次迭代中从每个源获得相同数量的PCM,如果一个源的数据用完了,就用0来填充。
要将两个字节
数组与16位声音样本混合,应首先将这些数组转换为int
数组,即基于样本的数组,然后将它们添加(混合),然后再转换回字节数组。从字节
数组转换为int
数组时,需要确保使用正确的尾数(字节顺序)。
这里有一些代码可以让你混合两个数组。最后有一些示例代码(使用正弦波)演示了该方法。请注意,这可能不是对其进行编码的理想方式,而是一个演示该概念的工作示例。按照菲尔的建议,使用流或线可能是更明智的整体方法。
祝你好运
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
public class MixDemo {
public static byte[] mix(final byte[] a, final byte[] b, final boolean bigEndian) {
final byte[] aa;
final byte[] bb;
final int length = Math.max(a.length, b.length);
// ensure same lengths
if (a.length != b.length) {
aa = new byte[length];
bb = new byte[length];
System.arraycopy(a, 0, aa, 0, a.length);
System.arraycopy(b, 0, bb, 0, b.length);
} else {
aa = a;
bb = b;
}
// convert to samples
final int[] aSamples = toSamples(aa, bigEndian);
final int[] bSamples = toSamples(bb, bigEndian);
// mix by adding
final int[] mix = new int[aSamples.length];
for (int i=0; i<mix.length; i++) {
mix[i] = aSamples[i] + bSamples[i];
// enforce min and max (may introduce clipping)
mix[i] = Math.min(Short.MAX_VALUE, mix[i]);
mix[i] = Math.max(Short.MIN_VALUE, mix[i]);
}
// convert back to bytes
return toBytes(mix, bigEndian);
}
private static int[] toSamples(final byte[] byteSamples, final boolean bigEndian) {
final int bytesPerChannel = 2;
final int length = byteSamples.length / bytesPerChannel;
if ((length % 2) != 0) throw new IllegalArgumentException("For 16 bit audio, length must be even: " + length);
final int[] samples = new int[length];
for (int sampleNumber = 0; sampleNumber < length; sampleNumber++) {
final int sampleOffset = sampleNumber * bytesPerChannel;
final int sample = bigEndian
? byteToIntBigEndian(byteSamples, sampleOffset, bytesPerChannel)
: byteToIntLittleEndian(byteSamples, sampleOffset, bytesPerChannel);
samples[sampleNumber] = sample;
}
return samples;
}
private static byte[] toBytes(final int[] intSamples, final boolean bigEndian) {
final int bytesPerChannel = 2;
final int length = intSamples.length * bytesPerChannel;
final byte[] bytes = new byte[length];
for (int sampleNumber = 0; sampleNumber < intSamples.length; sampleNumber++) {
final byte[] b = bigEndian
? intToByteBigEndian(intSamples[sampleNumber], bytesPerChannel)
: intToByteLittleEndian(intSamples[sampleNumber], bytesPerChannel);
System.arraycopy(b, 0, bytes, sampleNumber * bytesPerChannel, bytesPerChannel);
}
return bytes;
}
// from https://github.com/hendriks73/jipes/blob/master/src/main/java/com/tagtraum/jipes/audio/AudioSignalSource.java#L238
private static int byteToIntLittleEndian(final byte[] buf, final int offset, final int bytesPerSample) {
int sample = 0;
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
final int aByte = buf[offset + byteIndex] & 0xff;
sample += aByte << 8 * (byteIndex);
}
return (short)sample;
}
// from https://github.com/hendriks73/jipes/blob/master/src/main/java/com/tagtraum/jipes/audio/AudioSignalSource.java#L247
private static int byteToIntBigEndian(final byte[] buf, final int offset, final int bytesPerSample) {
int sample = 0;
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
final int aByte = buf[offset + byteIndex] & 0xff;
sample += aByte << (8 * (bytesPerSample - byteIndex - 1));
}
return (short)sample;
}
private static byte[] intToByteLittleEndian(final int sample, final int bytesPerSample) {
byte[] buf = new byte[bytesPerSample];
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
buf[byteIndex] = (byte)((sample >>> (8 * byteIndex)) & 0xFF);
}
return buf;
}
private static byte[] intToByteBigEndian(final int sample, final int bytesPerSample) {
byte[] buf = new byte[bytesPerSample];
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
buf[byteIndex] = (byte)((sample >>> (8 * (bytesPerSample - byteIndex - 1))) & 0xFF);
}
return buf;
}
public static void main(final String[] args) throws IOException {
final int sampleRate = 44100;
final boolean bigEndian = true;
final int sampleSizeInBits = 16;
final int channels = 1;
final boolean signed = true;
final AudioFormat targetAudioFormat = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
final byte[] a = new byte[sampleRate * 10];
final byte[] b = new byte[sampleRate * 5];
// create sine waves
for (int i=0; i<a.length/2; i++) {
System.arraycopy(intToByteBigEndian((int)(30000*Math.sin(i*0.5)),2), 0, a, i*2, 2);
}
for (int i=0; i<b.length/2; i++) {
System.arraycopy(intToByteBigEndian((int)(30000*Math.sin(i*0.1)),2), 0, b, i*2, 2);
}
final File aFile = new File("a.wav");
AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(a), targetAudioFormat, a.length),
AudioFileFormat.Type.WAVE, aFile);
final File bFile = new File("b.wav");
AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(b), targetAudioFormat, b.length),
AudioFileFormat.Type.WAVE, bFile);
// mix a and b
final byte[] mixed = mix(a, b, bigEndian);
final File outFile = new File("out.wav");
AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(mixed), targetAudioFormat, mixed.length),
AudioFileFormat.Type.WAVE, outFile);
}
}
问题内容: 在过去的几天里,尝试使其正常工作时遇到了麻烦。但是我想要的是我们有一个可以通过网络发送原始数据的应用程序。然后,我读入此二进制数据并将其保存到wav(任何音频)文件中。稍后可以查看压缩。 所以有问题的代码: 也尝试过使用上述声明,但是我得到了例外:。因此,我认为正在发生的事情是因为我的流是原始音频数据,并且没有wave报头,所以抛出异常? 该文件确实可以成功写入,但是它都是静态的,是否
我编写了代码将几个音频文件与1个图像组合成WebM视频。(audio1与默认jpg结合,audio2与默认jpg结合等)。 问题是,在此之后,视频长度比音频长度长25秒(因此音频在视频结束前缩短25秒)。 有没有办法在音频的同时停止视频?这是我使用的代码(我启动一个BAT命令文件)
问题内容: 给定一个包含压缩格式音频数据(例如MP3或OGG)的被叫,我希望创建一个包含输入数据的WAV转换的数组。不幸的是,如果您尝试执行此操作,JavaSound会给您以下错误: 通过将wav写入一个临时文件,然后将其读回,我设法使其正常工作,如下所示: 显然这是不太理想的。有没有更好的办法? 问题答案: 问题是,大多数AudioFileWriters在写入OutputStream时需要提前知
我有音频数据记录从麦克风这样:(ndarray的浮动) 这是我的代码: 但当我播放音频时,它就坏了,只有噪音。。。如何将其转换为。wav音频文件?
问题内容: 嗨,我需要将wav音频文件的采样率从44.1kHz下采样到8kHz。我必须使用字节数组手动完成所有工作…这是出于学术目的。 我目前正在使用2个类(接收器和源)来弹出和推送字节数组。一切顺利,直到到达需要使用线性插值对数据块进行下采样的部分为止。 由于我是从44100降采样到8000 Hz,因此我该如何插入一个包含约128000000字节的字节数组?现在,我弹出5、6或7个字节,具体取决
我正在使用这个方法将WAV文件读到字节数组(如下所示)。现在我已经将它存储在字节数组中,我想改变声音的音量。 编辑:根据要求提供音频格式的一些信息: