科大讯飞语音评测+录音

1.调用录音设备保存录音

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class MicroPhoneManager : MonoBehaviour
{

    public int DeviceLength;   
   
    private void Awake()
    {
        DontDestroyOnLoad(this);
        au= gameObject.GetComponent<AudioSource>();
        if (au == null)
        {
            au = gameObject.AddComponent<AudioSource>();
        }       
    }

    private int Frequency = 16000; //录音频率
    private int BitRate = 16; //比特率
    private int MicSecond = 180;  //每隔2秒,保存一下录音数据
    public Button bStart;
    public Button bStop;
    public Button bPlay;
    public Text tTip;
    private AudioSource au;
    private string[] devices;
    private bool isHaveMicrophone = false;
    void Start()
    {
        bStart.onClick.AddListener(OnStartClick);
        bStop.onClick.AddListener(OnStopClick);
        bPlay.onClick.AddListener(OnPlayClick);
        devices = Microphone.devices;
        DeviceLength = devices.Length;
        if (devices.Length > 0)

        {

            isHaveMicrophone = true;

            tTip.text = "设备有麦克风:" + devices[0];

        }

        else
        {

            isHaveMicrophone = false;

            tTip.text = "设备没有麦克风";

        }
    }
   
    void OnStartClick()
    {
        tTip.text += "\n开始录音....";
        au.Stop();
        au.loop = false;
        au.mute = true;
        //au.clip = Microphone.Start(devices[0], false, MicSecond, Frequency);
        StartMicrophone();
    }

    void OnStopClick()
    {
        tTip.text += "\n停止录音!";

        if (!Microphone.IsRecording(devices[0]))
            return;
        //Microphone.End(devices[0]);
        StopMicrophone();
        //au.Stop();
        Mp3FromClip("d:/test.mp3", au.clip); //将录音保存为mp3
        //WavFromClip(ClipPath, au.clip); //将录音保存为wav
    }
    string ClipPath
    {
        get
        {
            return Application.streamingAssetsPath + "/test.wav";
        }
    }
    void OnPlayClick()
    {
        if (Microphone.IsRecording(null))
            return;
        if (au.clip == null)
            return;
        au.mute = false;
        au.loop = false;
        au.Play();
        tTip.text += "\n播放录音....";
    }

    public delegate void AudioRecordHandle(AudioClip audioClip);
    public AudioSource audioSource;

    AudioClip micClip;


    bool isMicRecordFinished = true;

    List<float> micDataList = new List<float>();
    float[] micDataTemp;

    string micName;

    public void StartMicrophone()
    {
        if (isHaveMicrophone)
        {
            tTip.text += "\n找不到设备....";
            return;
        }
        StopCoroutine(StartMicrophone(null, PlayAudioRecord));
        StartCoroutine(StartMicrophone(null, PlayAudioRecord));
    }


    IEnumerator StartMicrophone(string microphoneName, AudioRecordHandle audioRecordFinishedEvent)
    {
        Debug.Log("Start Mic");
        micDataList = new List<float>();
        micName = microphoneName;
        micClip = Microphone.Start(micName, true, 2, 16000);
        isMicRecordFinished = false;
        int length = micClip.channels * micClip.samples;
        bool isSaveFirstHalf = true;//将音频从中间分生两段,然后分段保存
        int micPosition;
        while (!isMicRecordFinished)
        {
            if (isSaveFirstHalf)
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName); return micPosition > length * 6 / 10 && micPosition < length; });//保存前半段
                micDataTemp = new float[length / 2];
                micClip.GetData(micDataTemp, 0);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }
            else
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName); return micPosition > length / 10 && micPosition < length / 2; });//保存后半段
                micDataTemp = new float[length / 2];
                micClip.GetData(micDataTemp, length / 2);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }

        }
        micPosition = Microphone.GetPosition(micName);
        if (micPosition <= length)//前半段
        {
            micDataTemp = new float[micPosition / 2];
            micClip.GetData(micDataTemp, 0);
        }
        else
        {
            micDataTemp = new float[micPosition - length / 2];
            micClip.GetData(micDataTemp, length / 2);
        }
        micDataList.AddRange(micDataTemp);
        Microphone.End(micName);
        AudioClip newAudioClip = AudioClip.Create("RecordClip", micDataList.Count, 1, 16000, false);
        newAudioClip.SetData(micDataList.ToArray(), 0);
        audioRecordFinishedEvent(newAudioClip);
        Debug.Log("RecordEnd");
    }



    public void StopMicrophone()
    {
        Debug.Log("Stop mic");
        isMicRecordFinished = true;
    }

    void PlayAudioRecord(AudioClip newAudioClip)
    {
        au.clip = newAudioClip;
        au.Stop();
        //Mp3FromClip("d:/test.mp3", au.clip); //将录音保存为mp3
        WavFromClip(ClipPath, au.clip); //将录音保存为wav
    }

    public void WavFromClip(string WavPosition, AudioClip clip)
    {
        if (Microphone.IsRecording(null))
            return;
        Microphone.End(null);

        using (FileStream fs = CreateEmpty(WavPosition))
        {
            ConvertAndWrite(fs, au.clip);
            WriteHeader(fs, au.clip); //wav文件头
        }
    }

    private FileStream CreateEmpty(string filepath)
    {
        FileStream fileStream = new FileStream(filepath, FileMode.OpenOrCreate);
        byte emptyByte = new byte();

        for (int i = 0; i < 44; i++) //为wav文件头留出空间
        {
            fileStream.WriteByte(emptyByte);
        }

        return fileStream;
    }

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


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

    }
}

2.数据上传平台进行评测

using Newtonsoft.Json;
using System;
using System.Globalization;
using System.IO;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using UnityEngine;

namespace Ise
{
    public class WebYYPCPlus : Web
    {
        private const string hostUrl = "ws://ise-api.xfyun.cn/v2/open-ise";//开放评测地址
        private const string appid = "   ";//控制台获取    
        private const string apiSecret = "   ";//控制台获取  
        private const string apiKey = "   ";//控制台获取   

        private const string sub = "ise";//服务类型sub,开放评测值为ise
        private const string ent = "cn_vip";//语言标记参数 ent(cn_vip中文,en_vip英文)
        private const string rst = "entirety";//string 限制只能使用精简版 只有总分 entirety plain
        //题型、文本、音频要请注意做同步变更(如果是英文评测,请注意变更ent参数的值)
        private const string category = "read_chapter";//题型

        public const int StatusFirstFrame = 0;//第一帧
        public const int StatusContinueFrame = 1;//中间帧
        public const int StatusLastFrame = 2;//最后一帧
        ClientWebSocket ws = new ClientWebSocket();
        CancellationToken ct = new CancellationToken();
        private bool isSocket = false;

        //private IWebSocket socket;
        string log = "";
        public WebYYPCPlus(SetMessage value) : base(value)
        {
            //socket = new UnityWebSocket.WebSocket(getAuthUrl(hostUrl, apiKey, apiSecret));
            //socket.OnOpen += Socket_OnOpen;
            //socket.OnMessage += Socket_OnMessage;
            //socket.OnClose += Socket_OnClose;
            //socket.OnError += Socket_OnError;
            //AddLog(string.Format("Connecting...\n"));
            //socket.ConnectAsync();
        }
        public async void WebSocket()
        {
            try
            {
                //ClientWebSocket ws = new ClientWebSocket();
                //CancellationToken ct = new CancellationToken();
                string authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);

                Debug.Log(authUrl);
                Uri url = new Uri(authUrl);

                await ws.ConnectAsync(url, ct);
                //await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("hello")), WebSocketMessageType.Binary, true, ct); //发送数据
                isSocket = true;

                while (ws.State == System.Net.WebSockets.WebSocketState.Open)
                {
                    var result = new byte[1024];

                    await ws.ReceiveAsync(new ArraySegment<byte>(result), new CancellationToken());//接受数据
                    var str = Encoding.UTF8.GetString(result);//, 0, result.Length);
                    onMessage(str);

                }
            }
            catch (Exception ex)
            {
                Debug.Log(ex.Message);
            }
        }
        public override void Headers(string txtStr, string pathStr = "cn_chapter.wav")
        {
            //#if !UNITY_EDITOR && UNITY_WEBGL
            //isSocket = true;
            //#elif !NET_LEGACY
            isSocket = false;
            WebSocket();
            //#else
            //                        throw new Exception("Scripting Runtime Version should be .NET 4.x, via Menu:\nPlayerSettings -> Other Settings -> Script Runtime Version -> .Net 4.x Equivalent");
            //#endif
            onOpen(txtStr, pathStr);
        }
        public async void onOpen(string text, string pathStr = "cn_chapter.wav")
        {

            //连接成功,开始发送数据
            int frameSize = 1280; //每一帧音频的大小,建议每 40ms 发送 1280B
            int pcmCount = 0;
            int pcmSize = 0;
            int intervel = 10;
            int status = 0;  // 音频的状态
            string path = Application.streamingAssetsPath + "/Audio/" + pathStr;

            try
            { 
                _last = false;

                while (!isSocket)
                {
                    await Task.Delay(intervel);
                }

                ssb(text);

                byte[] arr = File.ReadAllBytes(path);
                if (arr==null)
                {
                    return;
                }
                pcmSize = arr.Length;
                string cc = Convert.ToBase64String(arr);
                while (true)
                {
                    if (pcmSize <= 2 * frameSize)
                    {
                        frameSize = pcmSize;
                        status = StatusLastFrame;
                    }
                    if (frameSize <= 0)
                    {
                        break;
                    }
                    byte[] buffer = new byte[frameSize];
                    Array.Copy(arr, pcmCount, buffer, 0, frameSize);
                    pcmCount += frameSize;
                    pcmSize -= frameSize;

                    switch (status)
                    {
                        case StatusFirstFrame:   // 第一帧音频status = 0
                            send(1, 1, Convert.ToBase64String(buffer));
                            status = StatusContinueFrame;//中间帧数
                            break;

                        case StatusContinueFrame:  //中间帧status = 1
                            send(2, 1, Convert.ToBase64String(buffer));
                            break;

                        case StatusLastFrame:    // 最后一帧音频status = 2 ,标志音频发送结束
                            send(4, 2, Convert.ToBase64String(buffer));
                            break;
                    }

                    await Task.Delay(intervel);

                }
            }
            catch (FileNotFoundException e)
            {
                SetMessage(e.Message);
            }
            catch (IOException e)
            {
                SetMessage(e.Message);

            }
            catch (Exception e)
            {
                SetMessage(e.Message);
            }

        }
        private void ssb(string text)
        {
            Root root = new Root()
            {
                common = new Common() { app_id = appid },
                business = new Business() { sub = sub, ent = ent, category = category, aue = "raw", auf = "audio/L16;rate=16000", rstcd = "utf8", cmd = "ssb", text = "\ufeff" + text, tte = "utf-8", ttp_skip = true, rst = rst },// , extra_ability = "syll_phone_err_msg", ise_unite="1" },
                data = new Data() { status = 0 }
            };

            var str = JsonConvert.SerializeObject(root);

            onSend(str);
        }
        public void send(int aus, int status, string data)
        {
            string str = "{\"business\": {\"cmd\": \"auw\", \"aus\":" + aus + " },\"data\":{\"status\": " + status + ",\"data\":\"" + data + "\"}}";

            onSend(str);
        }
        StringBuilder _json;
        bool _last = false;
        private void onMessage(string json)
        {

            Debug.Log(json);

            if (_last)
            {
                if (!json.Contains("{"))
                {
                    _json.Append(json);                   
                }
            }
            if (!_last && !json.Contains("null"))
            {
                //第一条最后结果
                _json = new StringBuilder(json);
                _last = true;
                string filePath = Application.streamingAssetsPath + "/StreamPlus.xml";
                FileStream fs = new FileStream(xmlPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                StreamWriter sw = new StreamWriter(fs);
                fs.SetLength(0);//首先把文件清空了。               
                sw.Close();
            }
            if (_last && _json.ToString().Contains("}}"))
            {
                _json.Replace("\0", "");
                json = _json.ToString();
               
                var resp = JsonConvert.DeserializeObject<IseNewResponseData>(json);

                if (resp.code != 0)
                {
                    Debug.LogError(json);
                }
                if (resp.data.status == 2)
                {

                    byte[] myByte = System.Convert.FromBase64String(resp.data.data);
                    string txt = Encoding.UTF8.GetString(myByte);
                    string filePath = Application.streamingAssetsPath + "/StreamPlus.xml";
                    File.AppendAllText(xmlPath, txt);
                    SetMessage(txt);
                    //AnalysisResultXML(xmlPath);
                    AudioManager.Ins.OnAnalysisResult(txt);
                    ws.Abort();
                } 
                _last = false;
            }

        }
        public void AnalysisResultXML(string path)
        {
            string[] read_chapter;
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(path);
                //获取根节点---此处一定要添加双斜杠
                XmlNodeList nodeList = doc.SelectNodes("//rec_paper");
               
                //遍历输出.
                foreach (XmlElement node in nodeList)
                {
                    string str = node.InnerXml.Split('>')[0];
                    read_chapter = str.Split(' ');
                    Syll.SetDic(read_chapter, Overall);
                    //输出结果
                    Debug.Log(Overall["total_score"] + "--" + Overall["tone_score"] + "--" + Overall["phone_score"] + "--"+ Overall["integrity_score"]);
                }
                 nodeList = doc.SelectNodes("//word");
                //遍历解析.
                foreach (XmlElement node in nodeList)
                {
                    Syll syll = new Syll(node.InnerXml);
                    if (!syll.IsCorrect)
                    {
                        wroingList.Add(syll.txtData);
                    }

                }

                AudioManager.Ins.OnAnalysisResult(Overall, wroingList);
 }
            catch (Exception ex)
            {               
                Debug.Log(ex.Message);
            }
        }
       

        string xmlPath
        {
            get
            {
                return Application.streamingAssetsPath + "/StreamPlus.xml";
            }
        }
        private void onSend(string json)
        {

            ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(json)), WebSocketMessageType.Binary, true, ct); //发送数据

        }
        public static string getAuthUrl(string hostUrl, string apiKey, string apiSecret)
        {
            Uri uri = new Uri(hostUrl);
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            string date = DateTime.UtcNow.ToUniversalTime().ToString(CultureInfo.CurrentCulture.DateTimeFormat.RFC1123Pattern, new System.Globalization.CultureInfo("en-us"));

            StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
                    Append("date: ").Append(date).Append("\n").//
                    Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");

            byte[] hexDigits;
            string sha;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
            {
                hexDigits = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString()));
                sha = Convert.ToBase64String(hexDigits);
            }

            string authorization = string.Format("hmac username=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", apiKey, "hmac-sha256", "host date request-line", sha);


            hostUrl += "?authorization=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization)) + "&date=" + date + "&host=" + uri.Host;

            return hostUrl;
        }
        private void AddLog(string str)
        {
            log += str;
            // max log
            if (log.Length > 32 * 1024)
            {
                log = log.Substring(16 * 1024);
            }
        }
        //private void Socket_OnOpen(object sender, OpenEventArgs e)
        //{
        //    SetMessage("打开" + sender.ToString());

        //}

        //private void Socket_OnMessage(object sender, MessageEventArgs e)
        //{
        //    //SetMessage();
        //    //string
        //}

        //private void Socket_OnClose(object sender, CloseEventArgs e)
        //{

        //}

        //private void Socket_OnError(object sender, UnityWebSocket.ErrorEventArgs e)
        //{
        //    SetMessage("错误" + sender.ToString());

        //}
        [Serializable]
        public class IseNewResponseData
        {
            public int code;
            public string message;
            public string sid;
            public ResPonseData data;
        }
        [Serializable]
        public class ResPonseData
        {
            public int status;
            public string data;
        }
    }
  public class Syll
        {
           
            public TxtData txtData = new TxtData();
            public Syll(string xml)
            {
                Dictionary<string, string> syll = new Dictionary<string, string>();
                Dictionary<string, string> phone = new Dictionary<string, string>();
                Dictionary<string, string> phone1 = new Dictionary<string, string>();
                List<string> sub_strs = new List<string>();
                string[] strs = xml.Split('>');
                for (int i = 0; i < strs.Length; i++)
                {
                    if (strs[i].Contains("time_len"))
                    {
                        sub_strs.Add(strs[i]);
                    }
                }
                SetDic(sub_strs[0].Split(' '), syll);
                SetDic(sub_strs[1].Split(' '), phone);
                SetDic(sub_strs[2].Split(' '), phone1);
                txtData.content = syll["content"];
                txtData.symbol = syll["symbol"];
                txtData.perr_msg = (Error)int.Parse(phone["perr_msg"]);
                txtData.tone_perr_msg = (Error)int.Parse(phone1["perr_msg"]);
            }
            public static void SetDic(string[] strs, Dictionary<string, string> dic)
            {
                for (int i = 0; i < strs.Length; i++)
                {
                    string str = strs[i];
                    if (str.Contains("="))
                    {
                        string[] sub_str = strs[i].Split('=');
                        dic.Add(sub_str[0].Replace("\"", string.Empty), sub_str[1].Replace("\"", string.Empty));
                    }
                }
            }
            public bool IsCorrect
            {
                get
                {
                    if (txtData.perr_msg != Error.Correct || txtData.tone_perr_msg != Error.Correct)
                    {
                        return false;
                    }
                    return true;
                }
            }
        }
       
    }
    public struct TxtData
    {
        public string content;
        public string symbol;
        public Error perr_msg;
        public Error tone_perr_msg;
    }
    public enum Error
    {
        Correct=0,
        ReadMiss = 16,
        AddRead= 32,
        BackwardRead= 64,
        Replace=128,
        Unison = 1,
        Pattern=2,
        UnisonPattern =3,
    }
}

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值