Unity

사운드 감지하기 1

psb08 2025. 2. 19. 14:12
728x90
반응형

마이크에서 소리를 감지하여 데시벨을 측정합니다.

 

MicVolume.cs

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class MicVolume : MonoBehaviour
{
    public string micDevice;
    public int sampleSize = 1024;
    public float waveformHeight = 5f;
    public float waveformWidth = 10f;
    public float updateSpeed = 0.1f;
    public float updateInterval = 0.5f;
    public LineRenderer lineRenderer;
    public TextMeshProUGUI volumeText;

    private AudioClip micClip;
    private float[] samples;
    private float[] smoothSamples;
    private float smoothedDb = 0f;
    private float lastUpdateTime = 0f;

    private void Start()
    {
        if (Microphone.devices.Length > 0)
        {
            micDevice = Microphone.devices[0];
            micClip = Microphone.Start(micDevice, true, 1, AudioSettings.outputSampleRate);
            samples = new float[sampleSize];
            smoothSamples = new float[sampleSize];
            lineRenderer.positionCount = sampleSize;
        }
        else
        {
            Debug.LogError("마이크를 찾을 수 없습니다.");
        }
    }

    private void Update()
    {
        if (micClip == null) return;

        int micPosition = Microphone.GetPosition(micDevice) - sampleSize;
        if (micPosition < 0) return;

        float volumeDb = GetMicVolumeDb();
        volumeDb = Mathf.Clamp(volumeDb + 80f, 0f, 120f); // 데시벨 범위 조정

        smoothedDb = Mathf.Lerp(smoothedDb, volumeDb, updateSpeed);

        if (smoothedDb > 70f) // 70dB 이상이면 로그 출력
        {
            Debug.Log($"[경고] 높은 소리 감지: {smoothedDb:F2} dB");
        }

        if (Time.time - lastUpdateTime >= updateInterval)
        {
            volumeText.text = $"소리 크기: <color=red>{smoothedDb:F2}</color> dB";
            lastUpdateTime = Time.time;
        }

        micClip.GetData(samples, micPosition);
        SmoothWaveform();
        DrawWaveform();
    }

    private float GetMicVolumeDb()
    {
        float[] samples = new float[sampleSize];
        int micPosition = Microphone.GetPosition(micDevice) - sampleSize;
        if (micPosition < 0) return 0f;

        micClip.GetData(samples, micPosition);
        float sum = 0f;
        for (int i = 0; i < sampleSize; i++)
        {
            sum += samples[i] * samples[i];
        }

        float rms = Mathf.Sqrt(sum / sampleSize);
        float db = 20 * Mathf.Log10(rms);
        return db;
    }

    private void SmoothWaveform()
    {
        for (int i = 0; i < sampleSize; i++)
        {
            smoothSamples[i] = Mathf.Lerp(smoothSamples[i], samples[i], updateSpeed);
        }
    }

    private void DrawWaveform()
    {
        float scaleX = waveformWidth / sampleSize;

        for (int i = 0; i < sampleSize; i++)
        {
            float x = i * scaleX - (waveformWidth / 2);
            float y = smoothSamples[i] * waveformHeight;
            lineRenderer.SetPosition(i, new Vector3(x, y, 0));
        }
    }

}

 


- using 부분

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

Unity에서 기본적으로 필요한 네임스페이스를 포함합니다.

 

TMP(TextMeshPro)를 사용해 UI에 마이크 볼륨을 표시하기 위해 TMPro 추가했습니다.

 

- 변수 선언

public string micDevice;

public int sampleSize = 1024;

public float waveformHeight = 5f;
public float waveformWidth = 10f;

사용할 마이크의 이름을 저장하는 변수.

 

오디오 샘플 크기. 클수록 정밀하지만 성능 부담이 증가.

 

오디오 파형(LineRenderer)의 높이와 너비를 조정하는 변수.

 

public float updateSpeed = 0.1f;
public float updateInterval = 0.5f;

public LineRenderer lineRenderer;
public TextMeshProUGUI volumeText;

private AudioClip micClip;
private float[] samples;
private float[] smoothSamples;

updateSpeed: 데시벨 변화 속도(보간).

updateInterval: UI 업데이트 간격(초 단위).

 

lineRenderer: 마이크 입력을 시각적으로 표현할 LineRenderer(파형 그리기).

volumeText: 현재 볼륨을 표시할 TextMeshProUGUI(UI 텍스트).

 

micClip: 마이크에서 수집한 오디오 데이터를 저장하는 변수.

samples: 현재 오디오 샘플 데이터를 저장하는 배열.

smoothSamples: 부드럽게 처리된 샘플 데이터 배열.

 

private float smoothedDb = 0f;
private float lastUpdateTime = 0f;

smoothedDb: 부드럽게 변화하는 데시벨 값.

lastUpdateTime: UI 업데이트를 제어하는 시간 변수.

 

- Start

private void Start()
{
    if (Microphone.devices.Length > 0)

마이크가 존재하는지 확인.

 

    {
        micDevice = Microphone.devices[0];
        
	micClip = Microphone.Start(micDevice, true, 1, AudioSettings.outputSampleRate);

첫 번째 마이크 장치를 선택.

 

마이크 녹음을 시작.

true : 루프 가능.

1 : 녹음 길이(초 단위).

AudioSettings.outputSampleRate : 오디오 샘플링 레이트 설정.

 

        samples = new float[sampleSize];
        smoothSamples = new float[sampleSize];
        lineRenderer.positionCount = sampleSize;
    }

샘플 데이터 배열을 초기화.

LineRenderer의 포인트 개수를 설정하여 파형을 그릴 준비.

 

    else
    {
        Debug.LogError("마이크를 찾을 수 없습니다.");
    }

마이크가 없으면 오류 메시지 출력.


너무 길어져서 다음 글에서 나머지 설명 하겠습니다.