melanchall / drywetmidi

.NET library to read, write, process MIDI files and to work with MIDI devices
https://melanchall.github.io/drywetmidi
MIT License
523 stars 73 forks source link

Midi Visualisation - Find all notes at current frame #214

Closed Ninjafox108 closed 1 year ago

Ninjafox108 commented 1 year ago

I'm very new to unity so this may be a problem with a simple solution, but nevertheless:

What is the best way to find all the notes (so you end up with a list of numbers) being played on any given frame. I have tried this: foreach (Note n in midiFile.GetNotes().AtTime<Note>(Time.time - startTime)) {} But that throws an error as the AtTime() Function requires a Long not a float. if I try to convert from Float to long (with foreach (Note n in midiFile.GetNotes().AtTime<Note>(((long)(Time.time - startTime))))) it just plays one note for a second and then stops. I would also like to have the audio play alongside the visualisation but that is not the priority.

This is my (not working) code so far:

public class Test2 : MonoBehaviour
{
    public GameObject cube;
    public float posMult = 10;
    public Playback playback;
    public float startTime;
    // Start is called before the first frame update
    void Start()
    {
        var midiFile = MidiFile.Read("Assets/Midi/midi.mid");
        // using (playback = midiFile.GetPlayback(OutputDevice.GetByIndex(0))) {
        //     playback.Speed = 1.0;
        //     playback.Play();
        // };
        startTime = Time.time;
    }
    // Update is called once per frame
    void Update()
    {
        var midiFile = MidiFile.Read("Assets/Midi/midi.mid");
        foreach (Note n in midiFile.GetNotes().AtTime<Note>(((long)(Time.time - startTime)))) {
            GameObject go = Instantiate(cube) as GameObject;
            Vector3 pos = go.transform.position;
            pos.x = (n.NoteNumber - 64) * posMult;
            pos.y = 10;
            pos.z = 0;
            go.transform.position = pos;

        }

        if (Input.anyKeyDown) {
            // playback.Stop();
            Application.Quit();
        }
    }
}

Any help would be greatly appreciated, Thanks in advance.

Ninjafox108 commented 1 year ago

It is worth saying that this is more likely something I don't know how to do than a problem with the software.

melanchall commented 1 year ago

First of all, you can see example of how to use Playback in Unity here: https://melanchall.github.io/drywetmidi/articles/dev/Using-in-Unity.html#example.

foreach (Note n in midiFile.GetNotes().AtTime<Note>(((long)(Time.time - startTime))))

Are you sure you want to get all notes every frame and search among all of them? Please see example at link above. You need to use NotesPlaybackStarted event of Playback to get information about currently played notes and doing some actions.

AtTime<Note>(Time.time - startTime)

What units of Time.time and startTime? You use method that takes long which is number of ticks. I suppose you want to pass milliseconds or seconds. Please see documentation on desired method.

Ninjafox108 commented 1 year ago

Are you sure you want to get all notes every frame and search among all of them?

I would both like to know what notes a currently playing and what notes have started playing. Thanks for the link and functions

You use method that takes long which is number of ticks.

How long is a tick?

melanchall commented 1 year ago

I would both like to know what notes a currently playing and what notes have started playing. Thanks for the link and functions

You just need to store notes in a list when they started playing and look into this list to know what notes are currently playing. And on notes finished playing, remove them from list. Right now you do a lot of calculations on every frame.

How long is a tick?

It depends on several things within a MIDI file. You should not think about them. Just use conversion API of the library: https://melanchall.github.io/drywetmidi/articles/high-level-managing/Time-and-length.html

Ninjafox108 commented 1 year ago

Ok, Thanks for all the help

melanchall commented 1 year ago

@Ninjafox108 any news?

Ninjafox108 commented 1 year ago

Sorry, I have been working on a different part of the project, I will have a go today

Ninjafox108 commented 1 year ago

I have had a go and I think I need to learn a bit more about unity and C# as a whole before giving this another go. Thank you for all the help.