2010-12-14 48 views

Répondre

0

Cette ressource, WAVE PCM soundfile format, m'a aidé à analyser les données PCM WAVE. J'ai construit une bibliothèque basée dessus et cela fonctionne bien pour moi.

+0

Pourriez-vous lier la mise en œuvre de votre bibliothèque? –

+0

@LeifGruenwoldt Ceci est une réponse de 5 ans, je suis désolé mais je ne l'ai pas autour. –

0

Je sais que l'un appelé « OperateWav » que je l'habitude de développer un convertisseur (linux c/C++) dans mon premier projet au cours de mes premiers internship.I ne sais pas si celui-ci existe en soi et si elle prend en charge java.Actually fichier wav est simplement l'ajout d'un en-tête de format wav sur les données brutes pcm ...

6

il est mon 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

Est-ce que 'get16BitPcm (short [])' fait juste un 'byte []' deux fois la taille de son paramètre? Si oui, quelle endianisme? Si non, que fait-il? – Scruffy

+0

@Scruffy Oui, et désolé pour manquant, méthode., Vient de mettre à jour ma réponse. – devflow

+0

Par http://soundfile.sapp.org/doc/WaveFormat, il semble que l'octet 16 dans l'en-tête devrait toujours être "16" pour PCM, quel que soit le nombre de bits par échantillon. – lreeder

0

Cela devrait être assez simple à faire parce que WAV = Métadonnées + PCM (dans cet ordre). Cela devrait fonctionner:

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)); 
    } 
} 

Comment utiliser

Il est très simple à utiliser. Il suffit d'appeler comme ceci:

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(); 
} 

Comment tout cela fonctionne

Comme vous pouvez le voir, l'en-tête de WAV est la seule différence entre les formats de fichiers WAV et PCM. L'hypothèse est que vous enregistrez 16 bits PCM MONO audio (qui selon votre code, vous êtes). La fonction rawToWave ajoute simplement des en-têtes au fichier WAV, afin que les lecteurs de musique sachent à quoi s'attendre lorsque votre fichier est ouvert, puis après les en-têtes, il écrit simplement les données PCM à partir du dernier bit.

Cool Tip

Si vous voulez changer le ton de votre voix, ou faire une application changeur de voix, tout ce que vous avez à faire est d'augmenter/diminuer la valeur du writeInt(output, 44100); // sample rate dans votre code. Diminuer cela indiquera au joueur de le jouer à un taux différent changeant ainsi la hauteur de sortie. Juste un petit quelque chose de plus intéressant à savoir. :)