zoukankan      html  css  js  c++  java
  • 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文件。

    样本数据

  • 相关阅读:
    SQL Server数据库查询区分大小写、全半角——排序规则的应用
    C#中查询字符串中是否包含指定字符/字符串,使用IndexOf还是Contains?
    【WM6.5】三星I8000按键码及窗体消息发送的方法备忘
    UoBlog 支持 MetaWeblog Api,可以使用 Windows Live Writer 离线发表日志
    C#中如何获取一个字符串的实际字符数
    使用HttpWebRequest发送HTTP请求,同时支持GET/POST方式提交。
    c#.NET中开发可用于Web网页的ActiveX控件
    CorePlex开发手记:一、Winform窗体皮肤及简单换肤机制
    .NET中简易实现线程安全
    在C#中截取指定长度的中文字符串(效率提高2500倍)
  • 原文地址:https://www.cnblogs.com/passedbylove/p/11208490.html
Copyright © 2011-2022 走看看