-
Notifications
You must be signed in to change notification settings - Fork 2
/
Mic.cs
106 lines (95 loc) · 3.58 KB
/
Mic.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Hypernex.Game.Audio;
using UnityEngine;
using Logger = Hypernex.CCK.Logger;
namespace Hypernex.Tools
{
[RequireComponent(typeof(DontDestroyMe))]
public class Mic : MonoBehaviour
{
public static Mic Instance;
public List<string> Devices => new(devices);
private List<string> devices = new();
public static string SelectedDevice { get; private set; }
public static bool IsRecording { get; private set; }
public static AudioClip Clip { get; private set; }
public static Action<float[], AudioClip, bool> OnClipReady { get; set; } = (data, clip, isEmpty) => { };
public static int Frequency { get; private set; }
public static int NumChannels => Clip.channels;
public static int FrameSizeMs { get; set; } = 40;
public static int SampleBufferSize => Mathf.RoundToInt(FrameSizeMs / 1000f * Frequency * NumChannels);
private int lastPosition;
public void SetDevice(string device)
{
if (Devices.Contains(device) && !IsRecording)
SelectedDevice = device;
}
public void StartRecording()
{
if (IsRecording || string.IsNullOrEmpty(SelectedDevice))
return;
IsRecording = true;
int minFrequency;
int maxFrequency;
Microphone.GetDeviceCaps(SelectedDevice, out minFrequency, out maxFrequency);
// UnityEngine.Debug.Log($"Min {minFrequency} Max {maxFrequency}");
Frequency = Mathf.Clamp(48000, minFrequency, maxFrequency);
Frequency = 48000;
// Frequency = 24000;
Clip = Microphone.Start(SelectedDevice, true, 10, Frequency);
}
private void Update()
{
if (!IsRecording)
return;
int position = Microphone.GetPosition(SelectedDevice);
if (position < 0)
return;
int offset = SampleBufferSize;
if (position >= offset)
{
int targetPos = (position - offset) / SampleBufferSize * SampleBufferSize;
int lastTargetPos = (lastPosition - offset) / SampleBufferSize * SampleBufferSize;
if (targetPos != lastTargetPos)
{
float[] data = new float[SampleBufferSize];
Clip.GetData(data, targetPos);
// UnityEngine.Debug.Log($"len {data.Length} pos {targetPos}");
OnClipReady.Invoke(data, Clip, false);
lastPosition = position;
}
}
}
public void StopRecording()
{
if (!IsRecording)
return;
Microphone.End(SelectedDevice);
IsRecording = false;
OnClipReady.Invoke(Array.Empty<float>(), Clip, true);
OpusAudioCodec.MicrophoneOff();
ConcentusAudioCodec.MicrophoneOff();
}
public void RefreshDevices() => devices = Microphone.devices.ToList();
private void Start()
{
if (Instance != null)
{
Logger.CurrentLogger.Warn("Cannot have more than one Mic Instance!");
Destroy(this);
}
Instance = this;
RefreshDevices();
if(devices.Count > 0)
SelectedDevice = devices[0];
}
private void OnDestroy()
{
if(IsRecording)
StopRecording();
}
}
}