使用安卓麦克风(Unity)进行吹气检测

时间:2015-07-19 13:40:22

标签: android unity3d detection particle-system

我正在尝试在Unity中创建一个程序(用于android),当吹出的音量超过x分贝时打开ParticleSystem。 我试图使用这个教程http://www.kaappine.fi/tutorials/using-microphone-input-in-unity3d/,但我没有相处...我很感激任何帮助。

1 个答案:

答案 0 :(得分:0)

您找到解决方案了吗?这是我的代码,但根据精度程度,这并不是我正在寻找的代码;

public class ballanimation : MonoBehaviour
private float targetTime = 0.0f;
// Start is called before the first frame update
public AudioSource source;
private const int SAMPLECOUNT = 1024;   // Sample Count.
private const float REFVALUE = 0.1f;    // RMS value for 0 dB.
private const float THRESHOLD = 0.02f;  // Minimum amplitude to extract pitch (recieve anything)
private const float ALPHA = 0.09f;      // The alpha for the low pass filter I don't really understand this

public int recordedLength ;    // How many previous frames of sound are analyzed.
public int requiedBlowTime;    // How long a blow must last to be classified as a blow (and not a sigh for instance).
public int clamp;            // Used to clamp dB (I don't really understand this either).

private float rmsValue;            // Volume in RMS
private float dbValue;             // Volume in DB
private float pitchValue;          // Pitch - Hz (is this frequency?)
private int blowingTime;           // How long each blow has lasted

private float lowPassResults;      // Low Pass Filter result
private float peakPowerForChannel; //

private GameObject[] cubes; // This is cubes array to show spectrum
public float SpectrumRefreshTime; // refresh rate to show cubes
private float lastUpdate = 0;
public float scaleFactor = 10000;
private float[] samples;           // Samples
private float[] spectrum = new float[1024];          // Spectrum
private List<float> dbValues;      // Used to average recent volume.
private List<float> pitchValues;   // Used to average recent pitch.

void Start()
{
    cubes = new GameObject[1024];
    samples = new float[SAMPLECOUNT];
    spectrum = new float[SAMPLECOUNT];
    dbValues = new List<float>();
    pitchValues = new List<float>();

    StartMicListener();

    foreach (var device in Microphone.devices) 
    {
        Debug.Log("Micro Connecté " + device);
    }   
}

private void StartMicListener() /// Starts the Mic, and plays the audio back in (near) real-time.
{
    source.clip = Microphone.Start(Microphone.devices[0], true, 999, AudioSettings.outputSampleRate);
    // HACK - Forces the function to wait until the microphone has started, before moving onto the play function.
    while (!(Microphone.GetPosition(Microphone.devices[0]) > 0))
    {
    }
    source.loop = true; 
    source.Play();
}

// Update is called once per frame
[System.Obsolete]
void Update()
{
    targetTime += Time.deltaTime;
    if (targetTime <= 10.0f)
    { gameStart(); }
    // If the audio has stopped playing, this will restart the mic play the clip.
    if (!source.isPlaying)
    {
        StartMicListener();
    }
    gameStart();
    // Gets volume and pitch values
    AnalyzeSound();
    // Runs a series of algorithms to decide whether a blow is occuring.
    DeriveBlow();
    // Update the meter display.
    Debug.Log("RMS (vol ): " + rmsValue.ToString("F2") + " Gain " + dbValue.ToString("F1") + " dB" + "  Pitch: " + pitchValue.ToString("F0") + " Hz");

    if (Time.time - lastUpdate > SpectrumRefreshTime)
    {
        source.GetSpectrumData(spectrum, 0, FFTWindow.Blackman);
        for (int i = 0; i < spectrum.Length; i++)
        {
            cubes[i].transform.localScale = new Vector3(1, spectrum[i] * scaleFactor, 1);
        }
        lastUpdate = Time.time;
    }
    createDisplayObjects();
}

void createDisplayObjects()
{
    for (int i = 0; i < 1024; i++)
    {
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.position = new Vector3(i, 0, 0);
        cubes[i] = cube;
    }
}

private void gameStart()
{
    
}

private void DeriveBlow()
{
    UpdateRecords(dbValue, dbValues);
    UpdateRecords(pitchValue, pitchValues);

    // Find the average pitch in our records (used to decipher against whistles, clicks, etc).
    float sumPitch = 0;
    foreach (float num in pitchValues)
    {
        sumPitch += num;
    }
    sumPitch /= pitchValues.Count;

    // Run our low pass filter.
    lowPassResults = LowPassFilter(dbValue);

    // Decides whether this instance of the result could be a blow or not.
    if (lowPassResults > -20  && sumPitch == 0) 
    {
        blowingTime += 1;
    } else
    {
        blowingTime = 0;
    }

    // Once enough successful blows have occured over the previous frames (requiredBlowTime), the blow is triggered.
    // This example says "blowing", or "not blowing", and also blows up a sphere.
    if (blowingTime > requiedBlowTime)
    {
        Debug.Log ( "Blowing");
        GameObject.FindGameObjectWithTag("Mongol").transform.localScale *= 1.012f;
        //GameObject.FindGameObjectWithTag("blow text").SetActive(false);
    }
    else
    {
        Debug.Log ( "Not blowing");
        GameObject.FindGameObjectWithTag("Mongol").transform.localScale *= 0.999f;
        
    }
}

// Updates a record, by removing the oldest entry and adding the newest value (val).
private void UpdateRecords(float val, List<float> record)
{
    if (record.Count > recordedLength)
    {
        record.RemoveAt(0);
    }
    record.Add(val);
}

/// Gives a result (I don't really understand this yet) based on the peak volume of the record
/// and the previous low pass results.
private float LowPassFilter(float peakVolume)
{
    return ALPHA * peakVolume + (1.0f - ALPHA) * lowPassResults;
}

private void AnalyzeSound()
{
    // Get all of our samples from the mic.
    source.GetOutputData(samples, 0);

    // Sums squared samples
    float sum = 0;
    for (int i = 0; i < SAMPLECOUNT; i++)
    {
        sum += Mathf.Pow(samples[i], 2);
    }

    // RMS is the square root of the average value of the samples.
    rmsValue = Mathf.Sqrt(sum / SAMPLECOUNT);
    dbValue = 20 * Mathf.Log10(rmsValue / REFVALUE); //calculate DB

    // Clamp it to {clamp} min
    if (dbValue < -clamp)
    {
        dbValue = -clamp;
    }

    // Gets the sound spectrum.
    source.GetSpectrumData(spectrum, 0, FFTWindow.BlackmanHarris);
    float maxV = 0;
    var maxN = 0;

    // Find the highest sample.
    for (int i = 0; i < SAMPLECOUNT; i++)
    {
        if ((spectrum[i] > maxV) || !(spectrum[i] > THRESHOLD))
            continue;
        maxV = spectrum[i];
        
        //float freqN = maxN;
        maxN = i;
    }
    float freqN = maxN;// Pass the index to a float variable
    // Interpolate index using neighbours
    if (maxN > 0 && maxN < SAMPLECOUNT - 1)
            {
                float dL = spectrum[maxN - 1] / spectrum[maxN];
                float dR = spectrum[maxN + 1] / spectrum[maxN];
                freqN += 0.5f * (dR * dR - dL * dL);
               // maxN = i; // maxN is the index of max
               // Convert index to frequency                   
            }
    pitchValue = freqN * (AudioSettings.outputSampleRate/2) / SAMPLECOUNT;
}