美文网首页
byte[]mp3,wav转为AudioClip

byte[]mp3,wav转为AudioClip

作者: 萧非子 | 来源:发表于2017-11-30 16:33 被阅读142次

using UnityEngine;
using UnityEngine.UI;
//using Baidu.Aip.Face;//人脸识别
//using Baidu.Aip.Ocr;//图片文字识别
using Baidu.Aip.Speech;//语音识别
using System.IO;
using Newtonsoft.Json;//解析返回json数据
using Newtonsoft.Json.Linq;//解析返回json数据
using NAudio.Wave;//mp3转wav;
using System.Collections;
using System.Collections.Generic;
using System;
using LitJson;//LitJson解析返回json数据

//百度语音识别接口调用——非子萧
public class BaiDuYYYY : MonoBehaviour
{
public static BaiDuYYYY _instance;
private static string[] micArray = null;//硬件设备——麦克风

public Text debugInfo;                             // 显示debug信息
private string infoLog = "";//日志信息
public Text asrText;                               //显示录音识别成功的文字
public Text inputField_text;                       //需要合成文本,的输入框文本

private FileInfo file;
private  Asr _asrClient;                          // 用来调用百度AI接口_语言识别
private  Tts _ttsClient;                          // 用来调用百度AI接口_语言合成

private Dictionary<string, object> options;       // 返回的数据
//private JObject result;                           // 接收返回的结果

private string ApiKey = "TvhA40Louirg9egVF2jRDVTG";//此处填写自己申请的key
private string SecretKey = "Z8umPDqzuuzoa7WafuHPEDjhl94uBflI";//此处填写自己申请的key

public static string ttString;//百度语言需要合成的文本,使用UTF-8编码,请注意文本长度必须小于1024字节

private string path;// = Application.dataPath + "/Resources/";//合成的语音文件保存的地址

private string ttsName_mp3;// = "xxmp3.mp3";//合成的语音文件保存的文件名
private string ttsName_wav;// = "xxmp3.wav";//合成的语音文件保存的文件名
private string arsName_wav;//= "arswav.wav";//识别的语言文件保存的w文件名;

private string mp3pathName;//合成的语言文件MP3=路径+文件名;
private string wavpathName;//合成的语言文件转wav=路径+文件名;

private string wavpathName2;//识别的语言文件wav=路径+文件名;(录音)

public  AudioSource _AudioSource;//播放组件
public  AudioSource _AudioSource2;//播放组件

private byte[] b; //百度语音合成返回byte[] 的MP3文件;
private static AudioClip _AudioClip;//百度语音需要识别的声音片段(录音文件),

private int audioLength=30;//录音的长度
private int frequency = 8000;//录音频率,一般44100,可以16000,8000;采用频率低,声音文件小

private void Awake()
{
    _instance = this;

    //网页端身份安全验证失败,我们需要在程序运行时手动添加安全证书,在Awake方法中加入
    System.Net.ServicePointManager.ServerCertificateValidationCallback +=
        delegate (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                    System.Security.Cryptography.X509Certificates.X509Chain chain,
                    System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            return true;           // always accept
        };

    _asrClient = new Asr(ApiKey, SecretKey);
     _ttsClient = new Tts(ApiKey, SecretKey);

    //path = Application.dataPath + "/Resources/";//合成的语音文件保存的地址(本地软件内)
    path =  Application.persistentDataPath +"/";//合成的语音文件保存的地址(pc沙盒)
    //path= Application.persistentDataPath + "/";//合成的语音文件保存的地址(android沙盒)
    ttsName_mp3 = "ttsmp3.mp3";//合成的语音文件保存的文件名
    ttsName_wav = "ttswav.wav";//合成的语音文件保存的文件名

    arsName_wav ="arswav.wav";//录音成功需要识别的语言文件名称
    mp3pathName = path + ttsName_mp3;
    wavpathName = path + ttsName_wav;
    wavpathName2 = path + arsName_wav;//百度语言已经识别的wav文件(路径+文件名)

    //_AudioSource = GetComponent<AudioSource>();

}
private void Start()
{
}

// 识别本地录音文件
public void AsrData()
{
    //var data = File.ReadAllBytes("语音pcm文件地址");
    //var result = _asrClient.Recognize(data, "pcm", 16000);
    //var path = Application.dataPath + "/Test/mywave.wav";//识别的格式:pcm 或者 wav 或者 amr
    var data = File.ReadAllBytes(wavpathName2);

     var result = _asrClient.Recognize(data, "wav", 8000);//百度语音识别

    //Newtonsoft.Json解析
    //JObject jobject = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(result.ToString());//json解析识别结果
    //string s = jobject["result"][0].ToString();//json解析识别为字符串string;

    //LitJson解析
    JsonData jd0 = JsonMapper.ToObject(result.ToString());//json解析json数据
    string s =jd0["result"][0].ToString();//json解析识别为字符串string;

    Debug.Log(s);//ok
    asrText.text = s;

    debugInfo.text = result.ToString();
    Debug.Log("识别本地文件");//ok     
}
// 识别URL中的语音文件
public void AsrUrl()
{
    var result = _asrClient.Recoginze(
        "http://xxx.com/待识别的pcm文件地址",
        "http://xxx.com/识别结果回调地址",
        "pcm",
        16000);
    // Console.WriteLine(result);
    Debug.Log("识别网络语音文件");//ok
}
// 合成
public void Tts()
{
    ttString = inputField_text.text;   //需要合成的文字为输入框输入的文字;
    //ttString = "好好工作,天天加班";
    // 可选参数
    var option = new Dictionary<string, object>()
{
    {"spd", 5}, // 语速int,取值0-9,默认为5中语速    
    {"pit", 5}, // 音调int,取值0-9,默认为5中语调
    {"vol", 7}, // 音量int,取值0-15,默认为5中音量
    {"per", 0}  // 发音人,发音人选择, 0为女声,1为男声,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女
};
    var result = _ttsClient.Synthesis(ttString, option);//百度语音识别

    if (result.ErrorCode == 0)  // 或 result.Success
    {          
        File.WriteAllBytes(mp3pathName, result.Data);//保存识别成功返回的语音文件(.MP3文件),语言文件写入本地
         b = result.Data;//百度语音合成返回byte[]的MP3文件;
       // UnityEditor.AssetDatabase.Refresh();//刷新,使刚创建的mp3立刻导入。接下来才可以被使用
    }

    Debug.Log(mp3pathName);//ok

    Debug.Log("文字合成语音文件MP3");//ok
}

//播放语言文件_mp3
public void PlayAudioMp3()
{
//string name = "ttsmp3";//合成的语音文件保存的文件名,(不需要后缀)

    //_AudioSource2.clip = Resources.Load(name, typeof(AudioClip)) as AudioClip;//Resources加载资源

    //Debug.Log(mp3pathName);

    //_AudioSource2.Play();//

    //Mp3ToWav();//mp3转wav,

    //file = new FileInfo(wavpathName);
    //Debug.Log(wavpathName);
    //DirectoryInfo mydir = new DirectoryInfo(wavpathName);
    //if (File.Exists(wavpathName))//判断一下本地是否有了该音频  如果有就不需下载  
    //{
    //    string s = @"file://" + wavpathName;
    //    StartCoroutine(LoadAudio());
    //}
    //Debug.Log("百度语音合成文件mp3播放");



    _AudioSource.clip = FromMp3Data(b);
    _AudioSource.Play();
}
//www加载资源
public IEnumerator LoadAudio()
{
    //string s = @"file://" + wavpathName;//android读取文件必须使用file:
    string s = wavpathName;//pc读取文件必须使用file:
    WWW www = new WWW(s);
    yield return www;
    // AudioClip ac = www.audioClip;
   AudioClip ac = WWWAudioExtensions.GetAudioClip(www);
  //  AudioClip ac = www.GetAudioClip(false, false);

    if (www.isDone)
    {
        _AudioSource2.clip = ac;
        _AudioSource2.Play();
    }
}
//播放语言文件_wav
public void PlayAudioWav()
{
    Mp3ToWav();//mp3转wav,

    //resource加载资源
     string name = "ttswav";//合成的语音文件保存的文件名,(不需要后缀)    
     _AudioSource2.clip = Resources.Load(name, typeof(AudioClip)) as AudioClip;
    _AudioSource2.Play();//ok

   // StartCoroutine(PlayAudioWaw2(wavpathName));
    Debug.Log("百度语音合成文件wav播放");
}
//mp3转wav,使用了库using NAudio.Wave
public void Mp3ToWav()
{
    var stream = File.Open(mp3pathName, FileMode.Open);
    var reader = new Mp3FileReader(stream);
    WaveFileWriter.CreateWaveFile(wavpathName, reader);
    stream.Close();
   // UnityEditor.AssetDatabase.Refresh();//刷新,使刚创建的mp3立刻导入。接下来才可以被使用
    Debug.Log("文件MP3转文件wav");//ok
}
// 获取麦克风设备
public void GetMicrophoneDevice()
{
    micArray = Microphone.devices;
    if (micArray.Length == 0)
    {
        Debug.LogError("找不到麦克风设备!");
        ShowInfoLog("找不到麦克风设备!");
        return;
    }
    else
    {
        Debug.Log("麦克风已经就绪,可以录音!");
        ShowInfoLog("麦克风已经就绪,可以录音!!");
        //return;
    }
}
//开始录音
public void StartRecord()
{
    GetMicrophoneDevice();//获取麦克风设备

    _AudioSource.Stop();//开始录音前,先停止上一个

    _AudioSource.loop = false;//循环=不
    _AudioSource.mute = true;//静音=是
    _AudioSource.clip = Microphone.Start(null, false, audioLength, frequency);//麦克风开始录音;参数:1,麦克风名称。2,循环.3,10秒录音计划长度,4,录音频率,一般44100,16000,8000;

    DateTime beginTime = DateTime.Now;
    _AudioClip = _AudioSource.clip;//录音的声音片段文件(以下操作的都是这个文件)
    while (!(Microphone.GetPosition(null) > 0))
    {
    }
    //播放录音
   // _AudioSource.Play();

    Debug.Log("开始录音!");
    ShowInfoLog("开始录音!");

    //倒计时——开始协程
   //StartCoroutine(TimeDown());
}
//协程--倒计时
IEnumerator TimeDown()
{
    Debug.Log("协程--倒计时");

    int time = 0;
    while (time < audioLength)
    {
        if (!Microphone.IsRecording(null))
        { //如果没有录制  
            Debug.Log("录音失败");
            yield break;
        }
        Debug.Log("yield return new WaitForSeconds " + time);
        yield return new WaitForSeconds(1);
        time++;
    }
    if (time >= audioLength)
    {
        Debug.Log("时间到,停止录音!");
        ShowInfoLog("时间到,停止录音!");

        StopRecord();//停止录音
        //SaveAudioClip();//保存录音
    }
    yield return 0;

    //int ShowTimeUI;
    //yield return new WaitForSeconds(0f);
    //for (float timer = 60; timer >= 0; timer -= Time.deltaTime)
    //{
    //    if (timer <= 60)
    //    {
    //        ShowTimeUI = (int)timer + 1;
    //        ShowUI.text = ShowTimeUI.ToString() + "秒";
    //    }
    //    yield return 0;
    //}
}
//停止录音
public void StopRecord()
{
    //if (micArray.Length == 0)
    //{
    //    return;
    //}
    //if (!Microphone.IsRecording(null))
    //{
    //    return;
    //}
     int lastPos = Microphone.GetPosition(null);
    if (Microphone.IsRecording(null))
    {
        audioLength = lastPos / frequency;//录音实际时长,string转int
    }
    else
    {
        audioLength = 30;//录音实际时长=录音计划时长
    }
    Microphone.End(null);//麦克风停止录音
    Debug.Log("停止录音");

    //Byte[] clipByte = GetClipData();//把录音转换为Byte[];

    //// private string speech;                          //本地语音文件的的二进制语音数据 ,需要进行base64 编码。与len参数连一起使用。
    ////private int len;                                //原始语音长度/本地语音文件的的字节数,单位字节

    //int len = clipByte.Length;//语音长度,int转string;
    //string speech = Convert.ToBase64String(clipByte); //音文件的的二进制语音数据 ,需要进行base64 编码。与len参数连一起使用。

    //Debug.Log("len" + len);//语音实际长度《语音计划长度
    //Debug.Log("audioLength" + audioLength);

}
//保存录音
public void SaveAudio_wav()
{
    Save(_AudioClip, wavpathName2);//保存录音
    //UnityEditor.AssetDatabase.Refresh();//刷新,使刚创建的mp3立刻导入。接下来才可以被使用
    Debug.Log("保存录音");
    ShowInfoLog("保存录音");
}
//wav保存,录音文件保存为wav文件
public static void Save(AudioClip clip, string path)
{
    string filePath = Path.GetDirectoryName(path);
    //如果文件目录不存在
    if (!Directory.Exists(filePath))
    {
        //创建文件
          Directory.CreateDirectory(filePath);
    }
    //创建一个空文件
    using (FileStream fileStream = CreateEmpty(path))
    {
        //写内容
        ConvertAndWrite(fileStream, clip);
        //写头文件
        WriteHeader(fileStream, clip);
    }
}
//wav保存,写内容
private static void ConvertAndWrite(FileStream fileStream, AudioClip clip)
{

    float[] samples = new float[clip.samples];

    clip.GetData(samples, 0);

    Int16[] intData = new Int16[samples.Length];

    Byte[] bytesData = new Byte[samples.Length * 2];

    int rescaleFactor = 32767; //to convert float to Int16  

    for (int i = 0; i < samples.Length; i++)
    {
        intData[i] = (short)(samples[i] * rescaleFactor);
        Byte[] byteArr = new Byte[2];
        byteArr = BitConverter.GetBytes(intData[i]);
        byteArr.CopyTo(bytesData, i * 2);
    }
    fileStream.Write(bytesData, 0, bytesData.Length);
}
//wav保存,创建空头
private static FileStream CreateEmpty(string filepath)
{
    FileStream fileStream = new FileStream(filepath, FileMode.Create);
    byte emptyByte = new byte();

    for (int i = 0; i < 44; i++) //preparing the header  
    {
        fileStream.WriteByte(emptyByte);
    }

    return fileStream;
}
//wav保存,写头文件
private static void WriteHeader(FileStream stream, AudioClip clip)
{
    int hz = clip.frequency;
    int channels = clip.channels;
    int samples = clip.samples;

    stream.Seek(0, SeekOrigin.Begin);

    Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
    stream.Write(riff, 0, 4);

    Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);
    stream.Write(chunkSize, 0, 4);

    Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
    stream.Write(wave, 0, 4);

    Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
    stream.Write(fmt, 0, 4);

    Byte[] subChunk1 = BitConverter.GetBytes(16);
    stream.Write(subChunk1, 0, 4);

    UInt16 two = 2;
    UInt16 one = 1;

    Byte[] audioFormat = BitConverter.GetBytes(one);
    stream.Write(audioFormat, 0, 2);

    Byte[] numChannels = BitConverter.GetBytes(channels);
    stream.Write(numChannels, 0, 2);

    Byte[] sampleRate = BitConverter.GetBytes(hz);
    stream.Write(sampleRate, 0, 4);

    Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels, here 44100*2*2  
    stream.Write(byteRate, 0, 4);

    UInt16 blockAlign = (ushort)(channels * 2);
    stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);

    UInt16 bps = 16;
    Byte[] bitsPerSample = BitConverter.GetBytes(bps);
    stream.Write(bitsPerSample, 0, 2);

    Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
    stream.Write(datastring, 0, 4);

    Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
    stream.Write(subChunk2, 0, 4);
}
// 回放录音

public void PlayRecordAudio()
{
if (Microphone.IsRecording(null))
return;
if (_AudioSource.clip == null)
return;
_AudioSource.mute = false;
_AudioSource.loop = false;
_AudioSource.Play();

    Debug.Log("回放录音");
    ShowInfoLog("回放录音");
}      
//显示日志提示信息
void ShowInfoLog(string info)
{
    debugInfo.text = "";
    infoLog += info;
    infoLog += "\r\n";
}
/// <summary>
/// 把录音转换为Byte[]
/// </summary>
/// <returns></returns>
public Byte[] GetClipData()
    {
        if (_AudioSource.clip == null)
        {
            Debug.LogError("录音数据为空");
            return null;
        }

        float[] samples = new float[_AudioSource.clip.samples];

         _AudioSource.clip.GetData(samples, 0);


        Byte[] outData = new byte[samples.Length * 2];

        int rescaleFactor = 32767; //to convert float to Int16   

        for (int i = 0; i < samples.Length; i++)
        {
            short temshort = (short)(samples[i] * rescaleFactor);

            Byte[] temdata = System.BitConverter.GetBytes(temshort);

            outData[i * 2] = temdata[0];
            outData[i * 2 + 1] = temdata[1];
        }
        if (outData == null || outData.Length <= 0)
        {
            Debug.LogError("录音数据为空");
            return null;
        }
        //return SubByte(outData, 0, audioLength * 8000 * 2);
        return outData;
    }

//文本合成语音并播放
public void TtsAndPlay()
{
    Tts();//百度文本合成
    PlayAudioMp3();//播放语音文件
}
//录音识别文本并显示
//在按钮上挂载OnButtonPressed脚本,按钮按下,开始录音,按钮抬起,录音结束开始语音识别,识别成功返回结果




//byte[]wav转为AudioClip
public static AudioClip FromWavData(byte[] data)
{
    WAV wav = new WAV(data);
    AudioClip audioClip = AudioClip.Create("wavclip", wav.SampleCount, 1, wav.Frequency, false);
    audioClip.SetData(wav.LeftChannel, 0);
    return audioClip;
}

//byte[]mp3转为AudioClip
public static AudioClip FromMp3Data(byte[] data)
{
    // Load the data into a stream  
    MemoryStream mp3stream = new MemoryStream(data);
    // Convert the data in the stream to WAV format  
    Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);

    WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(mp3audio);
    // Convert to WAV data  
    WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
    //Debug.Log(wav);  
    AudioClip audioClip = AudioClip.Create("testSound", wav.SampleCount, 1, wav.Frequency, false);
    audioClip.SetData(wav.LeftChannel, 0);
    // Return the clip  
    return audioClip;
}
//byte[] mp3转为AudioClip_byte[]mp3--wav
private static MemoryStream AudioMemStream(WaveStream waveStream)
{
    MemoryStream outputStream = new MemoryStream();
    using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
    {
        byte[] bytes = new byte[waveStream.Length];
        waveStream.Position = 0;
        waveStream.Read(bytes, 0, Convert.ToInt32(waveStream.Length));
        waveFileWriter.Write(bytes, 0, bytes.Length);
        waveFileWriter.Flush();
    }
    return outputStream;
}

}
//WAV类,
public class WAV
{
// convert two bytes to one float in the range -1 to 1
static float bytesToFloat(byte firstByte, byte secondByte)
{
// convert two bytes to one short (little endian)
short s = (short)((secondByte << 8) | firstByte);
// convert to range from -1 to (just below) 1
return s / 32768.0F;
}

static int bytesToInt(byte[] bytes, int offset = 0)
{
    int value = 0;
    for (int i = 0; i < 4; i++)
    {
        value |= ((int)bytes[offset + i]) << (i * 8);
    }
    return value;
}
// properties  
public float[] LeftChannel { get; internal set; }
public float[] RightChannel { get; internal set; }
public int ChannelCount { get; internal set; }
public int SampleCount { get; internal set; }
public int Frequency { get; internal set; }

public WAV(byte[] wav)
{

    // Determine if mono or stereo  
    ChannelCount = wav[22];     // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels  

    // Get the frequency  
    Frequency = bytesToInt(wav, 24);

    // Get past all the other sub chunks to get to the data subchunk:  
    int pos = 12;   // First Subchunk ID from 12 to 16  

    // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))  
    while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97))
    {
        pos += 4;
        int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
        pos += 4 + chunkSize;
    }
    pos += 8;

    // Pos is now positioned to start of actual sound data.  
    SampleCount = (wav.Length - pos) / 2;     // 2 bytes per sample (16 bit sound mono)  
    if (ChannelCount == 2) SampleCount /= 2;        // 4 bytes per sample (16 bit stereo)  

    // Allocate memory (right will be null if only mono sound)  
    LeftChannel = new float[SampleCount];
    if (ChannelCount == 2) RightChannel = new float[SampleCount];
    else RightChannel = null;

    // Write to double array/s:  
    int i = 0;
    int maxInput = wav.Length - (RightChannel == null ? 1 : 3);
    // while (pos < wav.Length)  
    while ((i < SampleCount) && (pos < maxInput))
    {
        LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
        pos += 2;
        if (ChannelCount == 2)
        {
            RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
            pos += 2;
        }
        i++;
    }
}
public override string ToString()
{
    return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel, RightChannel, ChannelCount, SampleCount, Frequency);
}

}

相关文章

网友评论

      本文标题:byte[]mp3,wav转为AudioClip

      本文链接:https://www.haomeiwen.com/subject/ggnvbxtx.html