// RobotSpeakerPublisher.cs
// copyright 2022- https://robot-creation-diary.com/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using RobotSpeakerMsg = RosMessageTypes.CppPubsub.RobotSpeakerMsgMsg;
using UnityEngine.XR;
using Node = UnityEngine.XR.XRNode;
public class RobotSpeakerPublisher : MonoBehaviour
{
ROSConnection ros;
public string topicName = "robot_speaker_topic";
public float publishMessageFrequency = 100.0f;
private float timeElapsed;
// オーディオソースコンポーネント
private AudioSource mAudioSource;
private int sample_rate;
private int recode_time;
// マイクのデバイス名
public string microphoneName = null;
public short[] audioData;
float mDebugStartTime;
public int debug_count;
public int audio_position;
private AudioClip mRecordedClip;
void Start()
{
mDebugStartTime = Time.realtimeSinceStartup;
this.debug_count = 0;
this.sample_rate = 44100;
this.recode_time = 10;
Debug.Log("-----------------------------");
mAudioSource = GetComponent<AudioSource>();
if (mAudioSource == null)
{
// AudioSourceが見つからない場合、新しく追加する
mAudioSource = gameObject.AddComponent<AudioSource>();
}
// マイクのデバイス名が指定されていない場合はデフォルトを使用
if (string.IsNullOrEmpty(microphoneName))
{
string[] microphoneDevices = Microphone.devices;
if (microphoneDevices.Length > 0)
{
// デフォルトのマイクを使用
microphoneName = microphoneDevices[0];
Debug.Log("Default Microphone: " + microphoneName);
// すべてのマイクの一覧を表示
Debug.Log("Available Microphones:");
foreach (string device in microphoneDevices)
{
Debug.Log(device);
}
}
else
{
Debug.LogError("No microphones available!");
}
}
this.mRecordedClip = Microphone.Start(microphoneName, true, this.recode_time, this.sample_rate);
this.mAudioSource.clip = this.mRecordedClip;
this.audio_position = 0;
while (!(Microphone.GetPosition(null) > 0)) { }
ros = ROSConnection.GetOrCreateInstance();
ros.RegisterPublisher<RobotSpeakerMsg>(topicName);
}
// Update is called once per frame
void Update()
{
timeElapsed += Time.deltaTime;
if (this.publishMessageFrequency < timeElapsed )
{
Debug.Log("timeElapsed " + timeElapsed + " " + this.publishMessageFrequency);
//音声データを設定
this.SetAudioData();
// Finally send the message to server_endpoint.py running in ROS
RobotSpeakerMsg outData = new RobotSpeakerMsg(
this.audioData,
this.debug_count
);
ros.Publish(topicName, outData);
timeElapsed = 0;
}
}
public void SetAudioData() {
if (0 < Microphone.GetPosition(null) | 0 < this.audio_position)
{
if (null != this.mAudioSource.clip)
{
//受け取り側と合わせるためにチャンネル数は確認しておくこと。
//Debug.Log("audio samples channels" + this.mAudioSource.clip.samples +" "+ this.mAudioSource.clip.channels);
int pos = Microphone.GetPosition(null);
int data_size_1 = 0;
int data_size_2 = 0;
//データサイズの計算
if (pos < this.audio_position)
{
data_size_1 = this.recode_time * this.sample_rate - this.audio_position;
//this.audio_position = 0;
data_size_2 = pos;
}
else {
data_size_1 = pos - this.audio_position;
}
if (pos <= 0) {
return;
}
if (data_size_1 <= 0) {
return;
}
///データの読み取り
float[] floatData_1 = new float[data_size_1];
float[] floatData_2 = new float[data_size_2];
this.mRecordedClip.GetData(floatData_1, this.audio_position);
//一周している時
if (pos < this.audio_position)
{
this.mRecordedClip.GetData(floatData_2, 0);
}
//データの型変換
this.audioData = new short[data_size_1+ data_size_2];
for (int i = 0; i < data_size_1; i++)
{
if (i < this.audioData.Length)
{
if (i < floatData_1.Length)
{
this.audioData[i] = (short)(floatData_1[i] * short.MaxValue);
}
}
}
//一周している時
if (pos < this.audio_position)
{
for (int i = 0; i < data_size_2; i++)
{
if (data_size_1 + i < this.audioData.Length)
{
if (i < floatData_2.Length)
{
this.audioData[data_size_1+ i] = (short)(floatData_2[i] * short.MaxValue);
}
}
}
}
this.debug_count++;//もとはデバッグ用だったが受け取り側で制御に使用しているので名前の変更が必要
this.audio_position = pos;
}
else
{
Debug.Log("is do");
}
}
}
}