我怎样才能使频率数组准确地描绘解码后的 mp3 文件?
How can I make an array of frequencies accurately depict a decoded mp3 file?
我正在使用 mp3spi 和 Triton,此代码将专门处理 192kbps 的 mp3 文件。
我面临的问题是 hz 的第一秒主要由以下内容组成:
0,0,0,0 或 255,255,255,255
我确实相信我可能没有跳过 header 正确,在这种情况下,频率并不是 mp3 在特定毫秒的真实描述。有没有人看到我跳过 header 的方式有什么问题,或者我如何将字节添加到数组中?
换句话说,我希望位置[0]的数组等于位置00:00:00的mp3,位置[44100]的数组等于恰好1秒的歌曲英寸
这是我用来从 mp3 文件读取字节并将其添加到数组列表字节的代码。
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class ReadMP3 {
private ArrayList<Integer> bytes = new ArrayList<>();
private AudioFormat decodedFormat;
public ReadMP3() throws UnsupportedAudioFileException, IOException {
String filename = new ReadFiles().getFile();
File file = new File(filename);
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioInputStream din = null;
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new
AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
this.decodedFormat = decodedFormat;
int i = 0;
while(true){
int currentByte = din.read();
if (currentByte == -1) {break;}
bytes.add(i, currentByte);
i++;
}
din.close();
in.close();
}
这是我代码的第二部分,我向数组的每个索引添加 4 个字节,这样 array.length / 44100 等于歌曲的长度(以秒为单位)。这意味着每个 array[i][4] 等于 1hz。
array[0][4] 到 array[44100][4] 是歌曲的第一秒。
public class AnalyzeMP3 {
//adds 4 bytes to offset[i], where each i represents 1hz,
//and 44100hz=1sec
public static int[][] calculate(ReadMP3 mp3) {
//calculates and prints how long the song is
double seconds = mp3.getBytes().size() /
mp3.getDecodedFormat().getFrameRate() / 4;
System.out.println("Length of song: " + (int)seconds + "s");
//adds 4 values to i through the whole song
int[][] offset = new int[mp3.getBytes().size()/4][4];
for(int i = 0; i < mp3.getBytes().size()/4; i++) {
for(int j = 0; j < 4; j++) {
offset[i][j] = mp3.getBytes().get(i+j);
}
}
return offset;
}
}
感谢 Brad 和 VC.One 让我意识到自己的错误。
首先,我必须像这样向 PCM-signed 编码添加正确的值:
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
(float)44.1, //samplerate
16, //sampleSizeInBits
2, //channels
626, //frameSize
(float)38.4615385, //frameRate
false); //bigEndian
然后我需要准确地表示数组中的 2 个通道。我上面在class AnalyzeMP3中的做法是错误的,应该这样添加:
//adds 4 values to i through the whole song
int[][] offset = new int[mp3.getBytes().size()/4][4];
int counter = 0;
for(int i = 0; i < mp3.getBytes().size()/4;i++) {
for(int j = 0; j < 4; j++) {
offset[i][j] = mp3.getBytes().get(counter);
counter++;
}
}
进行这些更改后,数组的大小为 4351104。 4351104 / 44100 等于以秒为单位的歌曲长度。并且没有 header 或任何我必须跳过的东西,该数组现在是整首歌曲的准确表示,每秒 44100 个频率。可以很容易地将其转换为将 10ms 表示为 441 个频率等。
我正在使用 mp3spi 和 Triton,此代码将专门处理 192kbps 的 mp3 文件。 我面临的问题是 hz 的第一秒主要由以下内容组成:
0,0,0,0 或 255,255,255,255
我确实相信我可能没有跳过 header 正确,在这种情况下,频率并不是 mp3 在特定毫秒的真实描述。有没有人看到我跳过 header 的方式有什么问题,或者我如何将字节添加到数组中?
换句话说,我希望位置[0]的数组等于位置00:00:00的mp3,位置[44100]的数组等于恰好1秒的歌曲英寸
这是我用来从 mp3 文件读取字节并将其添加到数组列表字节的代码。
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class ReadMP3 {
private ArrayList<Integer> bytes = new ArrayList<>();
private AudioFormat decodedFormat;
public ReadMP3() throws UnsupportedAudioFileException, IOException {
String filename = new ReadFiles().getFile();
File file = new File(filename);
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioInputStream din = null;
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new
AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
this.decodedFormat = decodedFormat;
int i = 0;
while(true){
int currentByte = din.read();
if (currentByte == -1) {break;}
bytes.add(i, currentByte);
i++;
}
din.close();
in.close();
}
这是我代码的第二部分,我向数组的每个索引添加 4 个字节,这样 array.length / 44100 等于歌曲的长度(以秒为单位)。这意味着每个 array[i][4] 等于 1hz。 array[0][4] 到 array[44100][4] 是歌曲的第一秒。
public class AnalyzeMP3 {
//adds 4 bytes to offset[i], where each i represents 1hz,
//and 44100hz=1sec
public static int[][] calculate(ReadMP3 mp3) {
//calculates and prints how long the song is
double seconds = mp3.getBytes().size() /
mp3.getDecodedFormat().getFrameRate() / 4;
System.out.println("Length of song: " + (int)seconds + "s");
//adds 4 values to i through the whole song
int[][] offset = new int[mp3.getBytes().size()/4][4];
for(int i = 0; i < mp3.getBytes().size()/4; i++) {
for(int j = 0; j < 4; j++) {
offset[i][j] = mp3.getBytes().get(i+j);
}
}
return offset;
}
}
感谢 Brad 和 VC.One 让我意识到自己的错误。 首先,我必须像这样向 PCM-signed 编码添加正确的值:
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
(float)44.1, //samplerate
16, //sampleSizeInBits
2, //channels
626, //frameSize
(float)38.4615385, //frameRate
false); //bigEndian
然后我需要准确地表示数组中的 2 个通道。我上面在class AnalyzeMP3中的做法是错误的,应该这样添加:
//adds 4 values to i through the whole song
int[][] offset = new int[mp3.getBytes().size()/4][4];
int counter = 0;
for(int i = 0; i < mp3.getBytes().size()/4;i++) {
for(int j = 0; j < 4; j++) {
offset[i][j] = mp3.getBytes().get(counter);
counter++;
}
}
进行这些更改后,数组的大小为 4351104。 4351104 / 44100 等于以秒为单位的歌曲长度。并且没有 header 或任何我必须跳过的东西,该数组现在是整首歌曲的准确表示,每秒 44100 个频率。可以很容易地将其转换为将 10ms 表示为 441 个频率等。