Как найти длину 2D-байтового массива и как использовать этот 2D-байтовый массив в ByteArrayInputStream
Во-первых, в следующем коде я пытаюсь найти длину двумерного байтового массива с помощью 'byteBuffer[0].length', но на самом деле он не работает. Когда я печатаю "byteBuffer [0].length", он выдает выходное значение 4 вместо 882000, что (последнее) должно быть правильным выходом в соответствии с параметрами, которые я передал. Так как мне повторить это в моем цикле?
Во-вторых, я хочу передать byteBuffer в ByteArrayInputStream, но в ByteArrayInputStream мы не можем передать 2D-массив. Так есть ли способ добавить значения и использовать его там? И мне также нужно передать значения 'Frequency1' и 'Frequency2' поочередно и сохранить их в формате.wav, чтобы я мог соответствующим образом воспроизвести их в моем медиаплеере. Например: сирена скорой помощи.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class AudioPlay {
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
final double SAMPLING_RATE = 44100; // Audio sampling rate
int time = in.nextInt(); //Time specified by user in seconds
int frequency1 = in.nextInt(); //Frequency specified by the user in hz
int frequency2 = in.nextInt();
//Size of buffer, in case time is 10 seconds it will be [2][441000]
float buffer[][] = new float[2][(int) (time * SAMPLING_RATE)];
for (int sample = 0; sample < buffer[0].length; sample++) {
double cycle = sample / SAMPLING_RATE; //Fraction of cycle between samples
buffer[0][sample] = (float) (Math.sin(2 * Math.PI * frequency1 * cycle)); //Storing value at every index of 1st row
buffer[1][sample] = (float) (Math.sin(2 * Math.PI * frequency2 * cycle)); //Storing value at every index of 2nd row
}
//Size of byteBuffer, in case time is 10sec it will be [2][882000]
byte byteBuffer[][] = new byte[2][(int)(buffer.length * 2)];
System.out.println(byteBuffer[0].length); // Giving wrong output
int count = 0;
for (int j = 0; j < byteBuffer.length; j++) {
for (int i = 0; i < byteBuffer[0].length; i++) {
final int x = (int) ((buffer[j][count++]) * Short.MAX_VALUE);
byteBuffer[j][i++] = (byte) x;
byteBuffer[j][i] = (byte) (x / 256); //Total Value of Byte
}
}
File out = new File("E:/RecordAudio7.wav"); //The path where user want the file data to be written
//Construct an audio format, using 44100hz sampling rate, 16 bit samples, mono, and big
// endian byte ordering
AudioFormat format = new AudioFormat((float) SAMPLING_RATE, 16, 1, true, false);
// It uses bytebuffer as its buffer array that contains bytes that may be read from the stream.
ByteArrayInputStream bais = new ByteArrayInputStream(byteBuffer[0]);
//Constructs an audio input stream that has the requested format and length in sample frames, using audio data
//from the specified input stream.
AudioInputStream audioInputStream = new AudioInputStream(bais, format, buffer.length);
//Writes a stream of bytes representing an audio file of the specified file type to the external file provided.
AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, out);
audioInputStream.close(); //Closes this audio input stream
}
}
2 ответа
Я разобрался с ответом на первую часть моего вопроса. Произошло лишь незначительное изменение в коде:
byte byteBuffer[][] = new byte[2][(int)(buffer[0].length * 2)];
вместо
byte byteBuffer[][] = new byte[2][(int)(buffer.length * 2)];
Декларирование byteBuffer
не правильно вы используете buffer.length
что 2, поэтому выход 4
использование buffer[0].length * 2
вместо buffer.length * 2
как показано ниже:
byte byteBuffer[][] = new byte[2][(int)(buffer[0].length * 2)];
для второй части (передача 2D-массива в ByteArrayInputStream) вы можете поместить 2D-элементы в одномерный более длинный массив, где его длина будет равна byteBuffer[0].length*byteBuffer.length
ты можешь использовать System.arraycopy()
что-то вроде этого:
int newArrayLength = byteBuffer.length*byteBuffer[0].length;
byte oneArray[] = new byte[newArrayLength];
//arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
for(int b=0;b<byteBuffer.length;b++){
System.arraycopy(byteBuffer[b], 0, oneArray, (b*byteBuffer[b].length), byteBuffer[b].length)
}
что этот код делает, конвертирует это
byteBuffer
(2D)
0- [] [] [] [] [] [] []...
1- [] [] [] [] [] [] []...
2- [] [] [] [] [] [] []...
в это:
oneArray
(1D)
[][][][][][][]...[][][][][][][]...[][][][][][][]...
И использовать oneArray
для тебя ByteArrayInputStream
PS: если ваше приложение продолжит работать после этого шага, хорошо освободить память, выделенную для byteBuffer
как это больше не нужно, потому что вы будете работать с oneArray
Вы можете освободить память, не ссылаясь на нее.
byteBuffer=null;