【山东大学软件学院创新项目实训】时空漫游 Unity使用麦克风录音

封装录音服务

封装类:

using System;
using UnityEngine;
 
public class MicrophoneWrapper : MonoSingleton<MicrophoneWrapper>
{
 
    private string TAG = "MicrophoneWrapper: ";
    //标记是否有麦克风
    private bool isHaveMic = false;
    //当前录音设备名称
    string currentDeviceName = string.Empty;
    //录音频率(音质)
    int recordFrequency = 8000;
    //上次按下时间戳
    double lastPressTimestamp = 0;
    //表示录音的最大时长
    int recordMaxLength = 10;
    //实际录音长度
    int trueLength = 0;
    //存储录音的片段
    [HideInInspector]
    public AudioClip saveAudioClip;
    // Start is called before the first frame update
    void Start()
    {
 
    }
 
    public void Init()
    {
        //获取麦克风设备,判断是否有麦克风设备
        if (Microphone.devices.Length > 0)
        {
            isHaveMic = true;
            currentDeviceName = Microphone.devices[0];
        }
        else {
            Debug.Log(TAG + " Microphone.devices is null(0) ");
        }
    }
 
    /// 按下录音按钮
    public void OnStartRecord()
    {
        StartRecording();
    }
 
    /// 放开录音按钮
    public AudioClip OnStopRecord()
    {
        trueLength = EndRecording();
        if (trueLength > 1)
        {
            Debug.Log(TAG+ " return AudioClip data ");
            return saveAudioClip;
        }
        Debug.Log(TAG + " return AudioClip is null ");
        return null;
    }
 
    /// 开始录音
    private bool StartRecording(bool isLoop = false) //8000,16000
    {
        Debug.Log(TAG+"StartRecording   ");
        if (isHaveMic == false || Microphone.IsRecording(currentDeviceName))
        {
            return false;
        }
        lastPressTimestamp = GetTimestampOfNowWithMillisecond();
        saveAudioClip = Microphone.Start(currentDeviceName, isLoop, recordMaxLength, recordFrequency);
        return true;
    }
    
    /// 录音结束, 返回实际的录音时长
    private int EndRecording()
    {
        Debug.Log(TAG+"EndRecording   ");
 
        if (isHaveMic == false || !Microphone.IsRecording(currentDeviceName))
        {
 
            Debug.Log(TAG + "EndRecording  Failed ");
 
            return 0;
        }
        //结束录音
        Microphone.End(currentDeviceName);
        //向上取整,避免遗漏录音末尾
        return Mathf.CeilToInt((float)(GetTimestampOfNowWithMillisecond() - lastPressTimestamp) / 1000f);
    }
    
    /// 计算按下录音时长
    private double GetTimestampOfNowWithMillisecond()
    {
        return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
    }
}

调用示例:

public class Test : MonoBehaviour,IPointerDownHandler,IPointerUpHandler
{
 
    private AudioSource mAudioSource;
    private AudioClip mAudioClip;
 
    void Start()
    {
        MicrophoneWrapper.Instance.Init();
        mAudioSource = GetComponent<AudioSource>();
    }
 
    public void OnPointerDown(PointerEventData eventData)
    {
        this.transform.GetChild(0).GetComponent<Text>().text = "松开播放";
        MicrophoneWrapper.Instance.OnStartRecord();
    }
 
    public void OnPointerUp(PointerEventData eventData)
    {
        this.transform.GetChild(0).GetComponent<Text>().text = "按下说话录音";
        mAudioClip = MicrophoneWrapper.Instance.OnStopRecord();
        if (mAudioSource != null && mAudioClip != null)
        {
            mAudioSource.PlayOneShot(mAudioClip);
        }
        else {
            Debug.Log(" mAudioSource or mAudioClip is null ");
        }
    }
}

生成文件与上传

把AudioClip转换为wav文件并上传至服务器

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

[RequireComponent(typeof(AudioSource))]
public class Speech2text : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    private AudioSource mAudioSource;
    private AudioClip mAudioClip;
    // 语音转换后的内容
    public Text speechContent;
    // 服务器地址
    public string url = "http://***.***.210.247:8086/getText";

    void Start()
    {
        // 这个路径在各平台有效
        Debug.Log("Audio saved at: " + Application.persistentDataPath);
        MicrophoneWrapper.Instance.Init();
        mAudioSource = GetComponent<AudioSource>();
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        this.transform.GetChild(0).GetComponent<Text>().text = "松开结束";
        MicrophoneWrapper.Instance.OnStartRecord();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        this.transform.GetChild(0).GetComponent<Text>().text = "按下说话";
        mAudioClip = MicrophoneWrapper.Instance.OnStopRecord();
        if (mAudioSource != null && mAudioClip != null)
        {
            mAudioSource.PlayOneShot(mAudioClip);
            // record
            string fileName = DateTime.UtcNow.Ticks + ".wav";
            string filePath = Path.Combine(Application.persistentDataPath, fileName);
            WavFromClip(filePath, mAudioClip);
            // upload
            StartCoroutine(sendWav(filePath, fileName));

        }
        else
        {
            Debug.Log(" mAudioSource or mAudioClip is null ");
        }
    }
    public void WavFromClip(string WavPosition, AudioClip clip)
    {
        if (Microphone.IsRecording(null))
            return;
        Microphone.End(null);

        using (FileStream fs = CreateEmpty(WavPosition))
        {
            ConvertAndWrite(fs, clip);
            WriteHeader(fs, clip); //wav文件头
        }
    }
    private FileStream CreateEmpty(string filepath)
    {
        FileStream fileStream = new FileStream(filepath, FileMode.Create);
        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);

    }
    IEnumerator sendWav(string filePath, string fileName)
    {
        byte[] wavFileBytes = File.ReadAllBytes(filePath);
        WWWForm form = new WWWForm();
        form.AddBinaryData("file", wavFileBytes, fileName);
        using (UnityWebRequest www = UnityWebRequest.Post(url, form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                string text = www.downloadHandler.text;
                Response res = JsonUtility.FromJson<Response>(text);
                speechContent.text = res.content;
            }
        }
    }
}
[Serializable]
class Response
{
    public bool success;
    public string content;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值