Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

[?]Escuchar cancion MIDI: Crear Thread para clase estática

Iniciado por kaito, Octubre 14, 2016, 01:29:25 PM

Tema anterior - Siguiente tema
Se pueden crear ritmos fácilmente desde un secuenciador MIDI del tipo bloques: https://onlinesequencer.net/
 
También podemos crear los típicos efectos de pulsación de botón, etc.. utilizando la notación musical americana: A,B,C,D,E,F,G y la escala 1-... entre los diferentes instrumentos musicales que facilite el plugin.
 
He encontrado este .dll plugin de 68KB de peso que funciona para Unity: http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/VisualStudio/HowToPlayMIDIInstruments con 125 instrumentos musicales.
 
El problema se produce cuando se abre un archivo .mid, canciones del formato MIDI, que deja congelado UNITY.
 
He intentado solucionar el problema creando un Thread utilizando System.Threading, directamente y desde una clase base que he encontrado en UnityAnswer.
 
Pero no funciona. Lo que he pensado es que el problema se encuentra en la clase estática MidiPlayer del plugin.
 
La pregunta: ¿Hay que crear de alguna manera especial el Thread de una clase estática?
 
Esto es lo que yo he hecho hasta ahora:
 

using UnityEngine;
using Toub.Sound.Midi;
using System.Collections;
using System.Threading;
public class PlayMusic : MonoBehaviour {
    public int escala = 3;
    //public KeyCode pressed;
    public GeneralMidiInstruments instrumento = GeneralMidiInstruments.AcousticGrand;
    public KeyCode[] teclas = new KeyCode[] {   KeyCode.Q,KeyCode.W,KeyCode.E,
                                                KeyCode.R,KeyCode.T,KeyCode.Y,
                                                KeyCode.U,KeyCode.I,KeyCode.O,
                                                KeyCode.P,KeyCode.Semicolon,KeyCode.Equals,
                                                KeyCode.Alpha2,KeyCode.Alpha3,
                                                KeyCode.Alpha5,KeyCode.Alpha6,KeyCode.Alpha7};
    private string[] notas = new string[] { "CX", "DX", "EX", "FX", "GX", "AX", "BX", "CY", "DY", "EY", "FY", "GY", "C#X", "D#X", "F#X", "G#X", "A#X" };
    private byte canal = 0;
    private PlayMIDI playMIDI;
    private Thread thread;
    private string path;
    // Use this for initialization
    void Start () {
       
        MidiPlayer.OpenMidi();
        MidiPlayer.Play(new ProgramChange(0, this.canal, this.instrumento));
        //this.path = Application.dataPath + "/cancion.mid";
        //Debug.Log(path);
        //this.thread = new Thread(func);
    }
    void func()
    {
        MidiPlayer.OpenMidi();
        MidiPlayer.Play(this.path);        
    }

// Update is called once per frame
void Update () {
        /*
        if (Input.anyKey)
        {
            KeyCode[] keys= System.Enum.GetValues(typeof(KeyCode)) as KeyCode[];
            for(int w = 0; w < keys.Length; w++)
           
                if (Input.GetKey(keys[w])) this.pressed = keys[w];
            }
        }
        */
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //this.playMIDI = new PlayMIDI(Application.dataPath + "/cancion.mid");
            //if (this.playMIDI.IsDone) this.playMIDI.Start();
            //this.playMIDI.Start();
            //this.thread.Start();
            Debug.Log("cancion");
        }
        for (int i=0;i<this.notas.Length;i++)
        {
           
            KeyCode k = this.teclas;
            if (Input.GetKeyDown(k))
            {
                string nota = this.notas.Replace("X", this.escala.ToString());
                nota = nota.Replace("Y", (this.escala + 1).ToString());
                this.StartCoroutine(this.Play(k, nota, this.canal));
            }
        }   
}
    IEnumerator Play(KeyCode key, string nota, byte canal)
    {
        MidiPlayer.Play(new NoteOn(0, canal, nota, 127));
        while (Input.GetKey(key)) yield return null;
        MidiPlayer.Play(new NoteOff(0, canal, nota, 127));
    }
   
       
    void OnDestroy()
    {
        MidiPlayer.CloseMidi();
    }
}

 
 
 
Para no empezar de cero, aquí dejo el enlace de descarga del proyecto con el plugin incluido: LINK

de pronto es complicarse mas pero con ILSpy puedes extraer el codigo fuente del plugin e intentar ejecutarlo en Unity, si logras compilar al menos puedes depurar un poco y mirar que hace y cual es el problema... te adelaté un poco el trabajo si te animas
//www.unityspain.com/applications/core/interface/file/attachment.php?id=10622">MIDI.7z

Julio 18, 2017, 09:59:04 AM #2 Ultima modificación: Julio 18, 2017, 10:25:12 AM por H@pesend
https://msdn.microsoft.com/es-es/library/system.threading.threadpool(v=vs.110).aspx
 
 
 
Con threadpool puedes lanzar metodos a hilos diferentes y filtrarlos por id, ademas puedes añadirle parametros al hilo...
 
Asi insertas un hilo en el pool de hilos, el threadpool gestiona el inicio y fin
 

public void HacerFelacion()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(_HacerFelacion), new object());
}
private void _HacerFelacion(object datosHilo)
{
//Insertar logica
}

 
Asi insertas un hilo en el pool de hilos, el threadpool gestiona el inicio y fin, pero si lanzas mas hilos, el _syncObj se encarga de bloquear el hilo para que no ejecute el siguiente hasta que se desbloquee
 

private readonly object _syncObj = new object();
public void HacerFelacion()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(_HacerFelacion), new object());
}
private void _HacerFelacion(object datosHilo)
{
lock (_syncObj)
    {
   //Insertar logica
    }
}

 
Asi insertas un hilo en el pool de hilos, el threadpool gestiona el inicio y fin, pero si lanzas mas hilos, el _syncObj se encarga de bloquear el hilo para que no ejecute el siguiente hasta que se desbloquee, ademas viene acompañado de una clase para rescatar parametros dentro del hilo
 

private readonly object _syncObj = new object();
private int indiceHilos = 0;
public void HacerFelacion()
{
ThreadInfo nuevoHilo = new ThreadInfo(new object(), ++indiceHilos);
    ThreadPool.QueueUserWorkItem(new WaitCallback(_HacerFelacion), nuevoHilo);
}
private void _HacerFelacion(object datosHilo)
{
lock (_syncObj)
    {
        ThreadInfo info = (ThreadInfo)datosHilo;
   //Logica
    }
}
public class ThreadInfo
{
public ThreadInfo(object parametros, int indice);
    public int indice { get; set; }
    public object parametros { get; set; }
}

 
 

Etiquetas: