Hi there!
I have an idea for app / game - who knows what it will be :).
I found some tutorials on YT - one, to make microphone input to visualize sound, and another to get some values of sound like spectrum range, loudness level (db values) and pitch value (height of sound).
And I merged these two things to get the pitch value from microphone input - and I get it, but with some issues…
First: _audioSource.clip = Microphone.Start(null, true, 1, AudioSettings.outputSampleRate);
the “1” is the record time in seconds. So, I understand, that the voice must be recorded (But really ?) so I set this to 1 s because I couldn’t set less value. Now I have a little reverb / echo effect… Is there any way to make it ‘real’ time ? In the inspector I have ‘loop’ option on only at Audio Source.
Second problem: I have 1:1 - position of ObjectPlayer (Sphere for now) in y axis related to pitch value. When I sing high - it goes high, when low - it goes low. But the pitch value gets also every scratches, noises so the ObjectPlayer jumps, shakes irregulary - in other words, it looks roughly, not what I want . I want to limit it only for a pure sing sound to get only music notes.
Im looking for the way, how to limit that to achieve full control of movement in easy way.
Here is my code of AudioAnalyser script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioAnalyser : MonoBehaviour
{
// Microphone input
public AudioClip _audioclip;
public bool _useMicrophone;
public string _selectedDevice;
private const int SAMPLE_SIZE = 1024;
public float rmsValue;
public float dbValue;
public float pitchValue;
private AudioSource _audioSource;
private float[] samples;
private float[] spectrum;
private float sampleRate;
private void Start()
{
_audioSource = GetComponent<AudioSource>();
// Microphone input
if (_useMicrophone)
{
if (Microphone.devices.Length > 0)
{
_selectedDevice = Microphone.devices[0].ToString();
//_audioSource.clip = Microphone.Start(_selectedDevice, true, 10, AudioSettings.outputSampleRate);
_audioSource.clip = Microphone.Start(null, true, 1, AudioSettings.outputSampleRate);
}
else
{
_useMicrophone = false;
}
}
if (!_useMicrophone)
{
//_audioSource.clip = _audioclip;
}
_audioSource.Play();
samples = new float[SAMPLE_SIZE];
spectrum = new float[SAMPLE_SIZE];
sampleRate = AudioSettings.outputSampleRate;
}
private void Update()
{
AnalyzeSound();
Debug.Log(pitchValue);
}
private void AnalyzeSound()
{
_audioSource.GetOutputData(samples, 0);
// Get the RMS
int i = 0;
float sum = 0;
for (; i < SAMPLE_SIZE; i++)
{
sum = samples[i] * samples[i];
}
rmsValue = Mathf.Sqrt(sum / SAMPLE_SIZE);
// Get the DB Value
dbValue = 20 * Mathf.Log10(rmsValue / 0.1f); // dbValue = 20 - default
//Get Sound Spctrum
_audioSource.GetSpectrumData(spectrum, 0, FFTWindow.BlackmanHarris);
//Find Pitch ////////////////////////////////////////////////////////////// <-
float maxV = 0;
var maxN = 0;
for (i = 0; i < SAMPLE_SIZE; i++)
{
if (!(spectrum[i] > maxV) || !(spectrum[i] > 0.0f))
continue;
maxV = spectrum[i];
maxN = i;
}
float freqN = maxN;
if (maxN > 0 && maxN < SAMPLE_SIZE - 1)
{
var dL = spectrum[maxN - 1] / spectrum[maxN];
var dR = spectrum[maxN + 1] / spectrum[maxN];
freqN += 0.5f * (dR * dR - dL * dL);
}
pitchValue = freqN * (sampleRate ) / SAMPLE_SIZE;
}
}
Also simply for testing script of Object movement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
//public Transform AudioAnalyser;
public Vector2 ppos;
void Start()
{
}
void Update()
{
GameObject theCamera = GameObject.Find("theCamera");
AudioAnalyser audioAnalyse = theCamera.GetComponent<AudioAnalyser>();
ppos = new Vector2(transform.position.x, audioAnalyse.pitchValue/50);
transform.position = ppos;
}
}
Anybody have an idea how to fix that ?
I just want to pure control of the playerObject by singing notes from my voice - without uncontrolled values from pitchvalue.
Here is the video how it works now: