[英]Java SFXR Port - Trouble writing byte[] to WAV file
我正在使用聲音效果生成器SFXR的Java端口,該端口涉及許多我不了解的奧秘音樂代碼,在涉及音頻方面是新手。 我所知道的是,該代碼可以使用SourceDataLine對象在Java中可靠地生成和播放聲音。
SDL對象使用的數據存儲在byte []中。 但是,僅將其寫到文件中是行不通的(大概是因為缺少WAV標頭,或者我認為是這樣)。
但是,我下載了此WAV讀/寫類: http : //computermusicblog.com/blog/2008/08/29/reading-and-writing-wav-files-in-java/ ,它在編寫WAV文件。 從SFXR提供byte []數據仍然會產生我無法使用的任何音樂播放器播放的文件。
我認為我一定會丟失一些東西。 這是播放聲音數據時的相關代碼:
public void play(int millis) throws Exception {
AudioFormat stereoFormat = getStereoAudioFormat();
SourceDataLine stereoSdl = AudioSystem.getSourceDataLine(stereoFormat);
if (!stereoSdl.isOpen()) {
try {
stereoSdl.open();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
if (!stereoSdl.isRunning()) {
stereoSdl.start();
}
double seconds = millis / 1000.0;
int bufferSize = (int) (4 * 41000 * seconds);
byte[] target = new byte[bufferSize];
writeBytes(target);
stereoSdl.write(target, 0, target.length);
}
那是從SFXR端口。 這是WavIO類的save()文件(當然,該類中還有很多其他代碼,我認為如果有人希望確切地了解緩沖區數據的處理方式,這可能值得發布:
public boolean save()
{
try
{
DataOutputStream outFile = new DataOutputStream(new FileOutputStream(myPath));
// write the wav file per the wav file format
outFile.writeBytes("RIFF"); // 00 - RIFF
outFile.write(intToByteArray((int)myChunkSize), 0, 4); // 04 - how big is the rest of this file?
outFile.writeBytes("WAVE"); // 08 - WAVE
outFile.writeBytes("fmt "); // 12 - fmt
outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4); // 16 - size of this chunk
outFile.write(shortToByteArray((short)myFormat), 0, 2); // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
outFile.write(shortToByteArray((short)myChannels), 0, 2); // 22 - mono or stereo? 1 or 2? (or 5 or ???)
outFile.write(intToByteArray((int)mySampleRate), 0, 4); // 24 - samples per second (numbers per second)
outFile.write(intToByteArray((int)myByteRate), 0, 4); // 28 - bytes per second
outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels
outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2); // 34 - how many bits in a sample(number)? usually 16 or 24
outFile.writeBytes("data"); // 36 - data
outFile.write(intToByteArray((int)myDataSize), 0, 4); // 40 - how big is this data chunk
outFile.write(myData); // 44 - the actual data itself - just a long string of numbers
}
catch(Exception e)
{
System.out.println(e.getMessage());
return false;
}
return true;
}
我所知道的是,我有很多數據,我希望它最終存儲在某種可播放的音頻文件中(此時,我會采用任何格式!)。 對我來說,將此字節緩沖區放入可播放文件的最佳方法是什么? 還是不是我認為的這個byte []?
我沒有太多機會使用Java的聲音功能,所以我將您的問題用作學習練習(希望您不要介意)。 您所引用的有關用Java讀取和寫入WAV文件的文章相對於Java歷史而言非常古老(1998年)。 另外,關於手動構造WAV標頭的事情也不太適合我(似乎有點容易出錯)。 由於Java是一種相當成熟的語言,因此我希望庫支持這種事情。
通過在互聯網上尋找示例代碼片段,我能夠從字節數組構造WAV文件。 這是我想出的代碼(我希望它不是最優的,但似乎可以工作):
// Generate bang noise data
// Sourced from http://www.rgagnon.com/javadetails/java-0632.html
public static byte[] bang() {
byte[] buf = new byte[8050];
Random r = new Random();
boolean silence = true;
for (int i = 0; i < 8000; i++) {
while (r.nextInt() % 10 != 0) {
buf[i] =
silence ? 0
: (byte) Math.abs(r.nextInt()
% (int) (1. + 63. * (1. + Math.cos(((double) i)
* Math.PI / 8000.))));
i++;
}
silence = !silence;
}
return buf;
}
private static void save(byte[] data, String filename) throws IOException, LineUnavailableException, UnsupportedAudioFileException {
InputStream byteArray = new ByteArrayInputStream(data);
AudioInputStream ais = new AudioInputStream(byteArray, getAudioFormat(), (long) data.length);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename));
}
private static AudioFormat getAudioFormat() {
return new AudioFormat(
8000f, // sampleRate
8, // sampleSizeInBits
1, // channels
true, // signed
false); // bigEndian
}
public static void main(String[] args) throws Exception {
byte[] data = bang();
save(data, "test.wav");
}
希望對您有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.