0
点赞
收藏
分享

微信扫一扫

WAV相关:从PCM16 Little Endian数据转WAV文件

数据格式

[0.0, -0.0, -0.0, 0.0, 0.0, 0.0, 5.960464477539063e-08, 5.960464477539063e-08, 1.1920928955078125e-07, 1.7881393432617188e-07, 2.384185791015625e-07,.....]

转换方法:c#

using System;
using System.IO;
using System.Text;

namespace deserialfromPCMData
{
public static class BinaryWriterExtensions
{
private const int HeaderSize = 44;

private const int Hz = 16000; //frequency or sampling rate

private const float RescaleFactor = 32767; //to convert float to Int16

public static void AppendWaveData<T>(this T stream, float[] buffer)
where T : Stream
{
if (stream.Length > HeaderSize)
{
stream.Seek(0, SeekOrigin.End);
}
else
{
stream.SetLength(HeaderSize);
stream.Position = HeaderSize;
}

// rescale
var floats = Array.ConvertAll(buffer, x => (short)(x * RescaleFactor));

// Copy to bytes
var result = new byte[floats.Length * sizeof(short)];
Buffer.BlockCopy(floats, 0, result, 0, result.Length);

// write to stream
stream.Write(result, 0, result.Length);

// Update Header
UpdateHeader(stream);
}

public static void UpdateHeader(Stream stream)
{
var writer = new BinaryWriter(stream);

writer.Seek(0, SeekOrigin.Begin);

writer.Write(Encoding.ASCII.GetBytes("RIFF")); //RIFF marker. Marks the file as a riff file. Characters are each 1 byte long.
writer.Write((int)(writer.BaseStream.Length - 8)); //file-size (equals file-size - 8). Size of the overall file - 8 bytes, in bytes (32-bit integer). Typically, you'd fill this in after creation.
writer.Write(Encoding.ASCII.GetBytes("WAVE")); //File Type Header. For our purposes, it always equals "WAVE".
writer.Write(Encoding.ASCII.GetBytes("fmt ")); //Mark the format section. Format chunk marker. Includes trailing null.
writer.Write(16); //Length of format data. Always 16.
writer.Write((short)1); //Type of format (1 is PCM, other number means compression) . 2 byte integer. Wave type PCM
writer.Write((short)1); //Number of Channels - 2 byte integer
writer.Write(Hz); //Sample Rate - 32 byte integer. Sample Rate = Number of Samples per second, or Hertz.
writer.Write(Hz * 2 * 1); // sampleRate * bytesPerSample * number of channels, here 16000*2*1.
writer.Write((short)(1 * 2)); //channels * bytesPerSample, here 1 * 2 // Bytes Per Sample: 1=8 bit Mono, 2 = 8 bit Stereo or 16 bit Mono, 4 = 16 bit Stereo
writer.Write((short)16); //Bits per sample (BitsPerSample * Channels) ?? should be 8???
writer.Write(Encoding.ASCII.GetBytes("data")); //"data" chunk header. Marks the beginning of the data section.
writer.Write((int)(writer.BaseStream.Length - HeaderSize)); //Size of the data section. data-size (equals file-size - 44). or NumSamples * NumChannels * bytesPerSample ??
}
} //end of class

using System;
using System.IO;
using System.Text;

namespace deserialfromPCMData
{
class SaveAudioStreamToWav
{
static void Main(string[] args)
{

Stream instream = File.OpenRead(@"g:\sample.txt");

BufferedStream bfs = new BufferedStream(instream);
byte[] array = new byte[bfs.Length];
instream.Read(array, 0, array.Length);

string str = Encoding.Default.GetString(array);

var StreamSample = str.Substring(1, str.Length - 2).Split(',');


var floatsArray = new float[StreamSample.Length];
floatsArray = Array.ConvertAll(StreamSample, x => (float)Convert.ToDouble(x));



using (var stream = new FileStream(@"g:\sample2.wav", FileMode.Create, FileAccess.ReadWrite))
{
stream.AppendWaveData(floatsArray);
}
}
}
}

 

 

Java方法:

 

package com;


import com.sun.media.sound.WaveFileWriter;
import org.junit.Test;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import java.io.*;
import java.util.Arrays;

//https://stackoverflow.com/questions/3599378/java-read-wav-file-as-a-float-array
//
//https://stackoverflow.com/questions/26824663/how-do-i-use-audio-sample-data-from-java-sound
//
//https://stackoverflow.com/questions/4440015/java-pcm-to-wav
public class TestWavFile {

//采样率16kHz
private float SAMPLING_RATE = 16000;
private float sampleSizeBits = 16;


//把short(2字节)拆解成字节流byte[2]
public byte[] get16BitPcm(short[] data) {

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

@Test
public void test() throws IOException{

BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
new FileInputStream("g:/sample.txt")));

StringBuffer buffer = new StringBuffer();
String line = null;

while ( (line = bufferedReader.readLine()) != null)
{
buffer.append(line);
}

int len = buffer.length();

String raw = buffer.substring(1,len-1);

Short[] data = Arrays.stream(raw.split(","))
.map(track->( Float.valueOf(track) * 0x7fff ))
.map(item->item.shortValue()).toArray(Short[]::new);

short [] frameData = new short[data.length];

for (int i = 0; i< data.length; i++) {
frameData[i] = data[i];
}

WaveFileWriter writer = new WaveFileWriter();

FileOutputStream outStream = new FileOutputStream("g:/sample.wav");
//(采样率,比特位,通道,是否有符号,大小端)
//比特位:short 2个字节 2*8 = 16
//是否有符号:是否有负数
//
AudioFormat format = new AudioFormat(SAMPLING_RATE,16,1,true,false);

AudioInputStream audioInputStream = new AudioInputStream(new ByteArrayInputStream(get16BitPcm(frameData)), format, frameData.length);

writer.write(audioInputStream, AudioFileFormat.Type.WAVE, outStream);

}
}

 java封装工具:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.media.sound.WaveFileWriter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

@Slf4j
public final class WavFileGenerator {



//采样率16kHz
private float SAMPLING_RATE = 16000;
private float sampleSizeBits = 16;

private int HeaderSize = 44;

//frequency or sampling rate
private int Hz = 16_000;

private byte[] values;


public WavFileGenerator(String ctx)
{
this(convert(ctx));
}
public WavFileGenerator(String []values)
{
convert(toPrimitive(Arrays.asList(values).stream().map(Float::valueOf).toArray(size -> new Float[size])));
}

public WavFileGenerator(short[] values)
{
/*sizeof(short) was 2 bytes in java platform*/
byte[] result = new byte[values.length * 2];

// 1short = 2bytes
int iter = 0;
for (short sample : values) {
result[iter++] = (byte)(sample & 0x00ff);
result[iter++] = (byte)((sample & 0xff00) >>> 8);
}

this.values = result;
}
public WavFileGenerator(float[] floatValues)
{
this(convert(floatValues));
}

static float[] toPrimitive(Float[] floats)
{
return ArrayUtils.toPrimitive(floats);
}

public static final short[] convert(float[] values)
{
//PCM 16bit little endian
short[] shortValues = new short[values.length];
for (int i = 0; i < values.length; i++) {
float value = values[i];
shortValues[i] = (short) (value < 0 ? value* 0x8000 : value*0x7fff);
}
return shortValues;
}

public static final float[] convert(String ctx)
{
ObjectMapper objectMapper = new ObjectMapper();
try {
Float[] data = objectMapper.readValue(ctx, Float[].class);
return toPrimitive(data);
} catch (IOException e) {
log.error("转换出错:{}",e);
}
return new float[0];
}

public byte[] getFmtChunk()
{
return null;
}

public byte[] getDataChunk()
{
return values;
}

void builder()
{

}

public ByteBuffer getAudioStream()
{
return null;
}

public void saveFile(String dest) throws IOException {

WaveFileWriter writer = new WaveFileWriter();
FileOutputStream outStream = new FileOutputStream(dest);
AudioFormat format = new AudioFormat(SAMPLING_RATE,16,1,true,false);
int frames = values.length / 2;
AudioInputStream audioInputStream = new AudioInputStream(new ByteArrayInputStream(values), format, frames);
writer.write(audioInputStream, AudioFileFormat.Type.WAVE, outStream);
audioInputStream.close();
outStream.close();
}
}

 

运行以上两个文件,最终会成功wav文件。

样本数据

举报

相关推荐

0 条评论