NeuroSky Mindwave Music Visualizer with Unity

时间:2017-04-05 19:35:20

标签: c# unity3d

我正在为学校的最后一个项目(艺术学校而不是计算机科学)工作,我想使用NeuroSky Mindwave脑读取器和Unity从脑波中制作一个实时可视化器。不幸的是,老师对编码知识非常有限,并且让我处于非常糟糕的位置......

我按照本教程制作了一个音乐可视化工具: https://www.youtube.com/watch?v=ELLANEFw5B8

并且还找到了一个示例Unity项目,它可以从脑波读取器中读取和显示原始数据: https://github.com/tgraupmann/unity_neurosky

我遇到的问题是尝试将我的可视化工具的输入更改为原始脑波数据而不是音乐。

有人能够帮助我推进这个项目吗?我已经查看了NeuroSky的Unity集成页面并通过电子邮件发送了它们没有成功。

非常感谢任何帮助,非常感谢!

音频频谱展示台代码

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

public class Spectrum : MonoBehaviour {

// Use this for initialization
public GameObject prefab;
public int numberOfObjects = 20;
public float radius = 5f;
public GameObject[] cubes;

void Start()
{
    for (int i = 0; i < numberOfObjects; i++)
    {
        float angle = i * Mathf.PI * 2 / numberOfObjects;
        Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
        Instantiate(prefab, pos, Quaternion.identity);
    }
    cubes = GameObject.FindGameObjectsWithTag ("cubes");
}

// Update is called once per frame
void Update () {
    float[] spectrum = AudioListener.GetSpectrumData (1024, 0, FFTWindow.Hamming);
    for(int i = 0; i < numberOfObjects; i++)
    {
        Vector3 previousScale = cubes[i].transform.localScale;
        previousScale.y = Mathf.Lerp (previousScale.y, spectrum[i] * 40, Time.deltaTime * 30);
        cubes[i].transform.localScale = previousScale;
    }       
  }
}

ThinkGear连接器控制器代码 (据我所知,导致原始数据在Unity中显示的文件,如下面的屏幕截图所示)

using System;
using System.Threading;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using MindWave.LitJson;
using System.Net.Sockets;
using System.Text;
using System.IO;

namespace MindWave
{
public class TGCConnectionController : MonoBehaviour
{
    private TcpClient client;
    private Stream stream;
    private byte[] buffer;

    public delegate void UpdateIntValueDelegate(int value);

    public delegate void UpdateFloatValueDelegate(float value);

    public event UpdateIntValueDelegate UpdatePoorSignalEvent;
    public event UpdateIntValueDelegate UpdateAttentionEvent;
    public event UpdateIntValueDelegate UpdateMeditationEvent;
    public event UpdateIntValueDelegate UpdateRawdataEvent;
    public event UpdateIntValueDelegate UpdateBlinkEvent;

    public event UpdateFloatValueDelegate UpdateDeltaEvent;
    public event UpdateFloatValueDelegate UpdateThetaEvent;
    public event UpdateFloatValueDelegate UpdateLowAlphaEvent;
    public event UpdateFloatValueDelegate UpdateHighAlphaEvent;
    public event UpdateFloatValueDelegate UpdateLowBetaEvent;
    public event UpdateFloatValueDelegate UpdateHighBetaEvent;
    public event UpdateFloatValueDelegate UpdateLowGammaEvent;
    public event UpdateFloatValueDelegate UpdateHighGammaEvent;

    private bool m_waitForExit = true;

    private void Start()
    {
        ThreadStart ts = new ThreadStart(Connect);
        Thread thread = new Thread(ts);
        thread.Start();
    }

    public void Disconnect()
    {
        stream.Close();
    }

    public void Connect()
    {
        client = new TcpClient("127.0.0.1", 13854);
        stream = client.GetStream();
        buffer = new byte[1024];
        byte[] myWriteBuffer = Encoding.ASCII.GetBytes(@"{""enableRawOutput"": true, ""format"": ""Json""}");
        stream.Write(myWriteBuffer, 0, myWriteBuffer.Length);

        while (m_waitForExit)
        {
            ParseData();
            Thread.Sleep(100);
        }
    }

    public class PowerData
    {
        public float delta = 0;
        public float theta = 0;
        public float lowAlpha = 0;
        public float highAlpha = 0;
        public float lowBeta = 0;
        public float highBeta = 0;
        public float lowGamma = 0;
        public float highGamma = 0;
        public PowerData()
        {
        }
    }

    public class SenseData
    {
        public int attention = 0;
        public int meditation = 0;
        public PowerData eegPower = null;
        public SenseData()
        {
        }
    }

    public class PackatData
    {
        public string status = string.Empty;
        public int poorSignalLevel = 0;
        public int rawEeg = 0;
        public int blinkStrength = 0;
        public SenseData eSense = null;
        public PackatData()
        {
        }
    }

    int GetObjectCount(String json)
    {
        int level = 0;
        int count = 0;
        for (int i = 0; i < json.Length; ++i)
        {
            if (json[i].Equals('{'))
            {
                if (level == 0)
                {
                    ++count;
                }
                ++level;
            }
            if (json[i].Equals('}'))
            {
                --level;
            }
        }
        return count;
    }

    private void ParseData()
    {
        if (stream.CanRead)
        {
            try
            {
                int bytesRead = stream.Read(buffer, 0, buffer.Length);

                List<PackatData> packets = new List<PackatData>();

                String packet = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                if (!string.IsNullOrEmpty(packet))
                {
                    Debug.Log(packet);
                    if (packet.Contains("}"))
                    {
                        int count = GetObjectCount(packet);
                        if (count == 1)
                        {
                            PackatData data = JsonMapper.ToObject<PackatData>(packet);
                            packets.Add(data);
                        }
                        else if (count > 1)
                        {
                            PackatData[] data = JsonMapper.ToObject<PackatData[]>(packet);
                            for (int index = 0; index < data.Length; ++index)
                            {
                                packets.Add(data[index]);
                            }
                        }
                    }
                }

                foreach (PackatData data in packets)
                {
                    if (null == data)
                    {
                        continue;
                    }
                    if (data.poorSignalLevel != 0)
                    {
                        Debug.Log("data.poorSignalLevel: " + data.poorSignalLevel);
                        if (null != UpdatePoorSignalEvent)
                        {
                            UpdatePoorSignalEvent.Invoke(data.poorSignalLevel);
                        }

                        if (null != data.eSense)
                        {
                            if (UpdateAttentionEvent != null)
                            {
                                UpdateAttentionEvent(data.eSense.attention);
                            }
                            if (UpdateMeditationEvent != null)
                            {
                                UpdateMeditationEvent(data.eSense.meditation);
                            }

                            if (null != data.eSense.eegPower)
                            {
                                if (UpdateDeltaEvent != null)
                                {
                                    UpdateDeltaEvent(data.eSense.eegPower.delta);
                                }
                                if (UpdateThetaEvent != null)
                                {
                                    UpdateThetaEvent(data.eSense.eegPower.theta);
                                }
                                if (UpdateLowAlphaEvent != null)
                                {
                                    UpdateLowAlphaEvent(data.eSense.eegPower.lowAlpha);
                                }
                                if (UpdateHighAlphaEvent != null)
                                {
                                    UpdateHighAlphaEvent(data.eSense.eegPower.highAlpha);
                                }
                                if (UpdateLowBetaEvent != null)
                                {
                                    UpdateLowBetaEvent(data.eSense.eegPower.lowBeta);
                                }
                                if (UpdateHighBetaEvent != null)
                                {
                                    UpdateHighBetaEvent(data.eSense.eegPower.highBeta);
                                }
                                if (UpdateLowGammaEvent != null)
                                {
                                    UpdateLowGammaEvent(data.eSense.eegPower.lowGamma);
                                }
                                if (UpdateHighGammaEvent != null)
                                {
                                    UpdateHighGammaEvent(data.eSense.eegPower.highGamma);
                                }
                            }


                        }
                    }
                    else if (data.rawEeg != 0)
                    {
                        if (null != UpdateRawdataEvent)
                        {
                            UpdateRawdataEvent(data.rawEeg);
                        }
                    }
                    else if (data.blinkStrength != 0)
                    {
                        if (null != UpdateRawdataEvent)
                        {
                            UpdateBlinkEvent(data.blinkStrength);
                        }
                    }
                }
            }
            catch (IOException e)
            {
                Debug.Log("IOException " + e);
            }
            catch (System.Exception e)
            {
                Debug.Log("Exception " + e);
            }
        }

    } // end ParseData

    void OnDisable()
    {
        m_waitForExit = false;
        Disconnect();
    }

    private void OnApplicationQuit()
    {
        m_waitForExit = false;
        Disconnect();
    }


}
}

1 个答案:

答案 0 :(得分:0)

我认为你错过了这个问题的信号处理。脑波(如果它的β波)具有相对较低的频率范围,约为15 Hz至30 Hz。另一方面,音乐是可听音,其频率范围在20 Hz到20,000 Hz之间。

我不熟悉你在这里提到的这个特定的可视化工具的实现,但是如果它被实现为可视化器想要做的那样,脑波应该只显示一些小的活动(取决于脑波的振幅)信号)在频谱的最低频率范围内。

有一个潜在的黑客来解决这个问题。通常,可视化器将使用FFT将时间序列信号转换为其频域,在此期间它将确定执行操作的频率范围。如果您可以在可视化器中找到代码并将频率范围更改为1 Hz到100 Hz,则应该看到合适的频谱。