I am making a MIDI visualizer, and I need for when a note plays (using CSharpSynth) a function is called. And it is, so that part is down. But what’s frustrating is trying to get that function to do something; currently, I am able to Debug.Log the current note that is being played, but when I put something in like set an object’s X position to the note number…
public void MidiNoteOnHandler(int channel, int note, int velocity)
{
transform.position = new Vector3(note, 0, 0);
}
I get an error:
get_transform can only be called from the main thread.
What’s the best way to get around this? Make a new script and then somehow whenever MidiNoteOnHandler is called it will fire it to another script? Sorry if my vocabulary is bad. Here’s the full script if needed.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using CSharpSynth.Effects;
using CSharpSynth.Sequencer;
using CSharpSynth.Synthesis;
using CSharpSynth.Midi;
[RequireComponent(typeof(AudioSource))]
public class MIDIPlayer : MonoBehaviour
{
//Public
//Check the Midi's file folder for different songs
public string midiFilePath = "Midis/Groove.mid";
//Try also: "FM Bank/fm" or "Analog Bank/analog" for some different sounds
public string bankFilePath = "GM Bank/gm";
public int bufferSize = 1024;
public int midiNote = 60;
public int midiNoteVolume = 100;
public int midiInstrument = 1;
//Private
private float[] sampleBuffer;
private float gain = 1f;
public MidiSequencer midiSequencer;
private StreamSynthesizer midiStreamSynthesizer;
private float sliderValue = 1.0f;
private float maxSliderValue = 127.0f;
//For animation
// Awake is called when the script instance
// is being loaded.
void Awake()
{
midiStreamSynthesizer = new StreamSynthesizer(44100, 2, bufferSize, 40);
sampleBuffer = new float[midiStreamSynthesizer.BufferSize];
midiStreamSynthesizer.LoadBank(bankFilePath);
LoadSong(midiFilePath);
//These will be fired by the midiSequencer when a note plays. Check the console for messages if you uncomment these
midiSequencer.NoteOnEvent += new MidiSequencer.NoteOnEventHandler (MidiNoteOnHandler);
midiSequencer.NoteOffEvent += new MidiSequencer.NoteOffEventHandler (MidiNoteOffHandler);
}
void LoadSong(string midiPath)
{
midiSequencer = new MidiSequencer(midiStreamSynthesizer);
midiSequencer.LoadMidi(midiPath, false);
midiSequencer.Play();
}
// Start is called just before any of the
// Update methods is called the first time.
void Start()
{
}
// Update is called every frame, if the
// MonoBehaviour is enabled.
void Update()
{
if (!midiSequencer.isPlaying)
//if (!GetComponent<AudioSource>().isPlaying)
LoadSong(midiFilePath);
}
// See http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnAudioFilterRead.html for reference code
// If OnAudioFilterRead is implemented, Unity will insert a custom filter into the audio DSP chain.
//
// The filter is inserted in the same order as the MonoBehaviour script is shown in the inspector.
// OnAudioFilterRead is called everytime a chunk of audio is routed thru the filter (this happens frequently, every ~20ms depending on the samplerate and platform).
// The audio data is an array of floats ranging from [-1.0f;1.0f] and contains audio from the previous filter in the chain or the AudioClip on the AudioSource.
// If this is the first filter in the chain and a clip isn't attached to the audio source this filter will be 'played'.
// That way you can use the filter as the audio clip, procedurally generating audio.
//
// If OnAudioFilterRead is implemented a VU meter will show up in the inspector showing the outgoing samples level.
// The process time of the filter is also measured and the spent milliseconds will show up next to the VU Meter
// (it turns red if the filter is taking up too much time, so the mixer will starv audio data).
// Also note, that OnAudioFilterRead is called on a different thread from the main thread (namely the audio thread)
// so calling into many Unity functions from this function is not allowed ( a warning will show up ).
private void OnAudioFilterRead(float[] data, int channels)
{
//This uses the Unity specific float method we added to get the buffer
midiStreamSynthesizer.GetNext(sampleBuffer);
for (int i = 0; i < data.Length; i++)
{
data <em>= sampleBuffer _* gain;_</em>
}
}
public void MidiNoteOnHandler(int channel, int note, int velocity)
{
* transform.position = new Vector3(note, 0, 0);*
}
public void MidiNoteOffHandler(int channel, int note)
{
}
}