使用百度語音實(shí)現(xiàn)的語音轉(zhuǎn)文字

在VR場景中我想把語音轉(zhuǎn)為文字,使用起來更高大上一點(diǎn)兒桑孩,于是拜鹤,我翻遍了目前用的比較多的集中SDK:科大訊飛,百度語音流椒,微軟TTS敏簿,親加通訊

其中,親加通訊和百度的SDK主要是面對移動(dòng)端宣虾,TTS主要面對Windows惯裕,科大訊飛移動(dòng)端桌面端都有。
我是想用到Oculus中的安岂,所以要選用windows轻猖,然后困難就來了。域那。

訊飛的桌面SDK是用C語言寫的咙边,想用到unity里面對于我這種一點(diǎn)兒C都不會(huì)的太難了猜煮,TTS沒怎么研究,但是感覺蠻復(fù)雜的败许,然后經(jīng)過我百般摸索王带,發(fā)現(xiàn)百度語音不光有移動(dòng)端,還有REST市殷,使用HTTP請求來使用的愕撰,不限平臺(tái)!

于是醋寝,我就決定采用百度的REST方式來實(shí)現(xiàn)語音轉(zhuǎn)為文字搞挣。

這個(gè)是使用文檔 自己看一下,下面我們直接上代碼

在unity中新建一個(gè)腳本

private string token;                           //access_token
private string cuid = "你自己隨便寫一個(gè)用戶標(biāo)識(shí)";        //用戶標(biāo)識(shí)
private string format = "wav";                  //語音格式
private int rate = 8000;                        //采樣率
private int channel = 1;                        //聲道數(shù)
private string speech;                          //語音數(shù)據(jù)音羞,進(jìn)行base64編碼
private int len;                                //原始語音長度
private string lan = "zh";                      //語種
 
private string grant_Type = "client_credentials";  
private string client_ID = "你的百度appkey";                       //百度appkey
private string client_Secret = "你的百度SecretKey";                   //百度Secret Key
 
private string baiduAPI = "http://vop.baidu.com/server_api";
private string getTokenAPIPath = "https://openapi.baidu.com/oauth/2.0/token";
 
private Byte[] clipByte;
 
/// <summary>
/// 轉(zhuǎn)換出來的TEXT
/// </summary>
public static string audioToString;
 
private AudioSource aud;
private int audioLength;//錄音的長度

以上是需要聲明的變量囱桨。其中AppID和SecretKey需要你注冊成為百度的開發(fā)者,然后再應(yīng)用管理中去看
繼續(xù)代碼:

/// <summary>
/// 獲取百度用戶令牌
/// </summary>
/// <param name="url">獲取的url</param>
/// <returns></returns>
private IEnumerator GetToken(string url)
{
    WWWForm getTForm = new WWWForm();
    getTForm.AddField("grant_type", grant_Type);
    getTForm.AddField("client_id", client_ID);
    getTForm.AddField("client_secret", client_Secret);
 
    WWW getTW = new WWW(url, getTForm);
    yield return getTW;
    if (getTW.isDone)
    {
        if (getTW.error == null)
        {
            token = JsonMapper.ToObject(getTW.text)["access_token"].ToString();
            StartCoroutine(GetAudioString(baiduAPI));
        }
        else
            Debug.LogError(getTW.error);
    }
}

上面這段代碼是獲取百度的Token嗅绰,有Token才有權(quán)使用API舍肠。

然后是發(fā)送轉(zhuǎn)換請求的方法:

/// <summary>
/// 把語音轉(zhuǎn)換為文字
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private IEnumerator GetAudioString(string url)
{
    JsonWriter jw = new JsonWriter();
    jw.WriteObjectStart();
    jw.WritePropertyName("format");
    jw.Write(format);
    jw.WritePropertyName("rate");
    jw.Write(rate);
    jw.WritePropertyName("channel");
    jw.Write(channel);
    jw.WritePropertyName("token");
    jw.Write(token);
    jw.WritePropertyName("cuid");
    jw.Write(cuid);
    jw.WritePropertyName("len");
    jw.Write(len);
    jw.WritePropertyName("speech");
    jw.Write(speech);
    jw.WriteObjectEnd();
 
    WWW getASW = new WWW(url, Encoding.Default.GetBytes(jw.ToString()));
    yield return getASW;
    if (getASW.isDone)
    {
        if (getASW.error == null)
        {
            JsonData getASWJson = JsonMapper.ToObject(getASW.text);
            if (getASWJson["err_msg"].ToString() == "success.")
            {
                audioToString = getASWJson["result"][0].ToString();
                if (audioToString.Substring(audioToString.Length - 1) == ",")
                    audioToString = audioToString.Substring(0, audioToString.Length - 1);
                Debug.Log(audioToString);
            }
        }
        else
        {
            Debug.LogError(getASW.error);
        }
    }
}

注意窘面,這里不能用WWWForm的AddField方法去上傳參數(shù)翠语,否則會(huì)返回錯(cuò)誤3300,也就是參數(shù)錯(cuò)誤财边,我就是在這卡住了很長時(shí)間肌括。。

好了制圈,現(xiàn)在就可以把一段語音轉(zhuǎn)換成文字然后返回到audioToString這個(gè)字符串了

然后是用unity錄音,這個(gè)腳本在之前的文章中寫過们童,下面在寫一遍

private void Awake()
{
    if (GetComponent<AudioSource>() == null)
        aud = gameObject.AddComponent<AudioSource>();
    else
        aud = gameObject.GetComponent<AudioSource>();
    aud.playOnAwake = false;
}

/// <summary>
/// 開始錄音
/// </summary>
public void StartMic()
{
    if (Microphone.devices.Length == 0) return;
    Microphone.End(null);
    Debug.Log("Start");
    aud.clip = Microphone.Start(null, false, 10, rate);
}

/// <summary>
/// 結(jié)束錄音
/// </summary>
public void EndMic()
{
    int lastPos = Microphone.GetPosition(null);
    if (Microphone.IsRecording(null))
        audioLength = lastPos / rate;//錄音時(shí)長  
    else
        audioLength = 10;
    Debug.Log("Stop");
    Microphone.End(null);
 
    clipByte = GetClipData();
    len = clipByte.Length;
    speech = Convert.ToBase64String(clipByte);
    StartCoroutine(GetToken(getTokenAPIPath));
}

/// <summary>
/// 把錄音轉(zhuǎn)換為Byte[]
/// </summary>
/// <returns></returns>
public Byte[] GetClipData()
{
    if (aud.clip == null)
    {
        Debug.LogError("錄音數(shù)據(jù)為空");
        return null;
    }
 
    float[] samples = new float[aud.clip.samples];
 
    aud.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("錄音數(shù)據(jù)為空");
        return null;
    }
 
    return outData;
}

然后再添加一下測試的代碼:

private void OnGUI()
{
    if (GUILayout.Button("Start"))
        StartMic();
 
    if (GUILayout.Button("End"))
        EndMic();
 
}
 
public Text debugText;
private void Update()
{
    debugText.text = audioToString;
}

整個(gè)腳本就完成了,然后把腳本掛到場景中一個(gè)物體上鲸鹦,再建一個(gè)Text,拖到debugText上慧库,運(yùn)行起來,點(diǎn)Start馋嗜,說一句話齐板,說完再點(diǎn)End,就會(huì)把說的話轉(zhuǎn)成語音輸出到debugText上

我覺得這個(gè)方法還是比較簡單的葛菇,只是必須要聯(lián)網(wǎng)才行甘磨,不過我們這個(gè)程序是要登陸注冊才能進(jìn)去的,所以不存在不聯(lián)網(wǎng)的問題眯停,大家可以參考參考济舆,有好的意見可以提出來共同提高

工程Demo地址請點(diǎn)這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莺债,隨后出現(xiàn)的幾起案子滋觉,更是在濱河造成了極大的恐慌签夭,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎侠,死亡現(xiàn)場離奇詭異第租,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)我纪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門慎宾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浅悉,你說我怎么就攤上這事趟据。” “怎么了术健?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵之宿,是天一觀的道長。 經(jīng)常有香客問我苛坚,道長,這世上最難降的妖魔是什么色难? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任泼舱,我火速辦了婚禮,結(jié)果婚禮上枷莉,老公的妹妹穿的比我還像新娘娇昙。我一直安慰自己,他們只是感情好笤妙,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布冒掌。 她就那樣靜靜地躺著,像睡著了一般蹲盘。 火紅的嫁衣襯著肌膚如雪股毫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天召衔,我揣著相機(jī)與錄音铃诬,去河邊找鬼。 笑死苍凛,一個(gè)胖子當(dāng)著我的面吹牛趣席,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醇蝴,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼宣肚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悠栓?” 一聲冷哼從身側(cè)響起霉涨,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤按价,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嵌纲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俘枫,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年逮走,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠蚪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡师溅,死狀恐怖茅信,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情墓臭,我是刑警寧澤蘸鲸,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站窿锉,受9級特大地震影響酌摇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗡载,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一窑多、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洼滚,春花似錦埂息、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铲掐,卻和暖如春拾弃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背迹炼。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工砸彬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斯入。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓砂碉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刻两。 傳聞我的和親對象是個(gè)殘疾皇子增蹭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容