2010-12-14 11 views

Antwort

0

Diese Ressource, WAVE PCM soundfile format, hat mir geholfen, PCM-Daten zu WAVE zu analysieren. Ich habe eine Bibliothek darauf aufgebaut und es funktioniert gut für mich.

+0

Könnten Sie Ihre Bibliotheksimplementierung verknüpfen? –

+0

@LeifGruenwoldt Dies ist eine 5 Jahre alte Antwort, es tut mir leid, aber ich habe sie nicht dabei. –

0

Ich kenne einen "OperateWav", den ich verwendet habe, um einen Konverter (Linux C/C++) in meinem ersten Projekt während meines ersten Praktikums zu entwickeln.Ich bin mir nicht sicher, ob dieses per se existiert und ob es java.Actually unterstützt WAV-Datei fügt einfach eine WAV-Format-Header auf pcm Rohdaten ...

6

es ist mein Code

/** 
* Write PCM data as WAV file 
* @param os Stream to save file to 
* @param pcmdata 8 bit PCMData 
* @param srate Sample rate - 8000, 16000, etc. 
* @param channel Number of channels - Mono = 1, Stereo = 2, etc.. 
* @param format Number of bits per sample (16 here) 
* @throws IOException 
*/ 
public void PCMtoFile(OutputStream os, short[] pcmdata, int srate, int channel, int format) throws IOException { 
    byte[] header = new byte[44]; 
    byte[] data = get16BitPcm(pcmdata); 

    long totalDataLen = data.length + 36; 
    long bitrate = srate * channel * format; 

    header[0] = 'R'; 
    header[1] = 'I'; 
    header[2] = 'F'; 
    header[3] = 'F'; 
    header[4] = (byte) (totalDataLen & 0xff); 
    header[5] = (byte) ((totalDataLen >> 8) & 0xff); 
    header[6] = (byte) ((totalDataLen >> 16) & 0xff); 
    header[7] = (byte) ((totalDataLen >> 24) & 0xff); 
    header[8] = 'W'; 
    header[9] = 'A'; 
    header[10] = 'V'; 
    header[11] = 'E'; 
    header[12] = 'f'; 
    header[13] = 'm'; 
    header[14] = 't'; 
    header[15] = ' '; 
    header[16] = (byte) format; 
    header[17] = 0; 
    header[18] = 0; 
    header[19] = 0; 
    header[20] = 1; 
    header[21] = 0; 
    header[22] = (byte) channel; 
    header[23] = 0; 
    header[24] = (byte) (srate & 0xff); 
    header[25] = (byte) ((srate >> 8) & 0xff); 
    header[26] = (byte) ((srate >> 16) & 0xff); 
    header[27] = (byte) ((srate >> 24) & 0xff); 
    header[28] = (byte) ((bitrate/8) & 0xff); 
    header[29] = (byte) (((bitrate/8) >> 8) & 0xff); 
    header[30] = (byte) (((bitrate/8) >> 16) & 0xff); 
    header[31] = (byte) (((bitrate/8) >> 24) & 0xff); 
    header[32] = (byte) ((channel * format)/8); 
    header[33] = 0; 
    header[34] = 16; 
    header[35] = 0; 
    header[36] = 'd'; 
    header[37] = 'a'; 
    header[38] = 't'; 
    header[39] = 'a'; 
    header[40] = (byte) (data.length & 0xff); 
    header[41] = (byte) ((data.length >> 8) & 0xff); 
    header[42] = (byte) ((data.length >> 16) & 0xff); 
    header[43] = (byte) ((data.length >> 24) & 0xff); 

    os.write(header, 0, 44); 
    os.write(data); 
    os.close(); 
} 

EDIT: 2016-01-11

public byte[] get16BitPcm(short[] data) { 
    byte[] resultData = new byte[2 * data.length]; 
    int iter = 0; 
    for (double sample : data) { 
     short maxSample = (short)((sample * Short.MAX_VALUE)); 
     resultData[iter++] = (byte)(maxSample & 0x00ff); 
     resultData[iter++] = (byte)((maxSample & 0xff00) >>> 8); 
    } 
    return resultData; 
} 
+0

Ist 'get16BitPcm (short [])' nur ein 'byte []' doppelt so groß wie der Parameter? Wenn ja, welche Endianz? Wenn nicht, was macht es? – Scruffy

+0

@Scruffy Ja, und Entschuldigung für fehlende, Methode., Nur meine Antwort aktualisiert. – devflow

+0

Pro http://soundfile.sapp.org/doc/WaveFormat scheint es so, als ob Byte 16 im Header immer "16" für PCM sein sollte, unabhängig von der Anzahl der Bits pro Sample. – lreeder

0

Dies sollte ziemlich einfach sein, weil WAV = Metadaten + PCM (in dieser Reihenfolge). Dies sollte funktionieren:

private void rawToWave(final File rawFile, final File waveFile) throws IOException { 

byte[] rawData = new byte[(int) rawFile.length()]; 
DataInputStream input = null; 
try { 
    input = new DataInputStream(new FileInputStream(rawFile)); 
    input.read(rawData); 
} finally { 
    if (input != null) { 
     input.close(); 
    } 
} 

DataOutputStream output = null; 
try { 
    output = new DataOutputStream(new FileOutputStream(waveFile)); 
    // WAVE header 
    // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 
    writeString(output, "RIFF"); // chunk id 
    writeInt(output, 36 + rawData.length); // chunk size 
    writeString(output, "WAVE"); // format 
    writeString(output, "fmt "); // subchunk 1 id 
    writeInt(output, 16); // subchunk 1 size 
    writeShort(output, (short) 1); // audio format (1 = PCM) 
    writeShort(output, (short) 1); // number of channels 
    writeInt(output, 44100); // sample rate 
    writeInt(output, RECORDER_SAMPLERATE * 2); // byte rate 
    writeShort(output, (short) 2); // block align 
    writeShort(output, (short) 16); // bits per sample 
    writeString(output, "data"); // subchunk 2 id 
    writeInt(output, rawData.length); // subchunk 2 size 
    // Audio data (conversion big endian -> little endian) 
    short[] shorts = new short[rawData.length/2]; 
    ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts); 
    ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2); 
    for (short s : shorts) { 
     bytes.putShort(s); 
    } 

    output.write(fullyReadFileToBytes(rawFile)); 
} finally { 
    if (output != null) { 
     output.close(); 
    } 
} 
} 
byte[] fullyReadFileToBytes(File f) throws IOException { 
int size = (int) f.length(); 
byte bytes[] = new byte[size]; 
byte tmpBuff[] = new byte[size]; 
FileInputStream fis= new FileInputStream(f); 
try { 

    int read = fis.read(bytes, 0, size); 
    if (read < size) { 
     int remain = size - read; 
     while (remain > 0) { 
      read = fis.read(tmpBuff, 0, remain); 
      System.arraycopy(tmpBuff, 0, bytes, size - remain, read); 
      remain -= read; 
     } 
    } 
} catch (IOException e){ 
    throw e; 
} finally { 
    fis.close(); 
} 

return bytes; 
} 
private void writeInt(final DataOutputStream output, final int value) throws IOException { 
output.write(value >> 0); 
output.write(value >> 8); 
output.write(value >> 16); 
output.write(value >> 24); 
} 

private void writeShort(final DataOutputStream output, final short value) throws IOException { 
output.write(value >> 0); 
output.write(value >> 8); 
} 

private void writeString(final DataOutputStream output, final String value) throws IOException { 
for (int i = 0; i < value.length(); i++) { 
    output.write(value.charAt(i)); 
    } 
} 

Wie

verwenden Es ist ganz einfach zu bedienen. nennen Sie es einfach wie folgt aus:

File f1 = new File("/sdcard/44100Sampling-16bit-mono-mic.pcm"); // The location of your PCM file 
File f2 = new File("/sdcard/44100Sampling-16bit-mono-mic.wav"); // The location where you want your WAV file 
try { 
rawToWave(f1, f2); 
} catch (IOException e) { 
e.printStackTrace(); 
} 

Wie das alles

funktioniert Wie Sie der einzige Unterschied zwischen WAV und PCM-Dateiformaten sehen können, ist die WAV-Header. Die Annahme ist, dass Sie 16 Bit PCM MONO Audio aufnehmen (was nach Ihrem Code, Sie sind). Die rawToWave-Funktion fügt der WAV-Datei einfach Header hinzu, so dass Musik-Player wissen, was zu erwarten ist, wenn Ihre Datei geöffnet wird, und nach den Headern schreibt sie einfach die PCM-Daten ab dem letzten Bit.

kühle Spitze

Wenn Sie die Tonhöhe Ihrer Stimme verschieben möchten, oder eine Sprachwechsler App machen, alles, was Sie zu tun ist erhöhen/den Wert von writeInt(output, 44100); // sample rate in Ihrem Code zu verringern. Wenn Sie es verringern, wird der Player aufgefordert, es mit einer anderen Rate abzuspielen und dadurch die Tonhöhe des Ausgangs zu ändern. Nur ein kleines Extra "Gut zu wissen". :)