Git Product home page Git Product logo

Comments (7)

davidluzgouveia avatar davidluzgouveia commented on September 24, 2024

The time that is stored in the MIDI file is measured in an abstract time unit known as the "tick" and unless there is a bug MidiEvent.Time should be giving you the exact tick in which the event occurs.

Isn't that what you're getting?

If you're talking about "clock" time, that data is not stored in the MIDI file, it needs to be calculated after loading the entire file, based on the TicksPerQuarterNote value, a combination of all Tempo MetaEvents up to the event, and the absolute tick of the event.

Same thing with note length, there is no such thing in a MIDI file. You need to look ahead and find the closest Note Off event on the same channel and with the same note as the Note On event, and subtract the two absolute times to know the duration in ticks.

This project is just a simple parser which reads the MIDI data as close as possible to the original representation, so it doesn't do any extra calculations.

I've considered adding these extra calculations as extensions when I have some time but at the time they're outside the scope of the parser.

from midi-parser.

shinkuan avatar shinkuan commented on September 24, 2024
foreach (var track in midiFile.Tracks)
        {
            
            int[] NoteOnWait = new int[256]; //time = [Note]
            foreach (var midiEvent in track.MidiEvents)
            {
                if (midiEvent.MidiEventType == MidiEventType.NoteOn)
                {
                    var time = midiEvent.Time;
                    var channel = midiEvent.Channel;
                    var note = midiEvent.Note;
                    var velocity = midiEvent.Velocity;
                    NoteOnWait[note] = time;
                }

                if (midiEvent.MidiEventType == MidiEventType.NoteOff)
                {
                    var time = midiEvent.Time;
                    var channel = midiEvent.Channel;
                    var note = midiEvent.Note;
                    var velocity = midiEvent.Velocity;
                    var length = time - NoteOnWait[note];

                    // And Some Code here:
                    // Visualize objects:
                    // Object coordinate = (note, NoteOnWait[note]); (x,y)
                    // Size = (x, length)
                }
            }

And here is the results: (Green is my visualizer)
It seems notes time which inside same beat were very close to each other, while notes time with different beat is opposite.

MIDI_2_1
MDID_2_2

Midi_1
MIDI_2

I add the time value next to the objects
Midi_1

from midi-parser.

davidluzgouveia avatar davidluzgouveia commented on September 24, 2024

Can you share the midi file? I might have some time to look at it over the weekend.

But if the time values on your last screenshot are the time values in midi-parser, then it looks like the problem should be on your rendering code.

Edit: Nevermind, those tick numbers are increasing too fast, it has to be a bug.

from midi-parser.

shinkuan avatar shinkuan commented on September 24, 2024

Here is the link to the MIDI file:
https://drive.google.com/file/d/1lBDBtNm2Gdg2fh9DMLZnrcFHjzTLPUzF/view?usp=sharing

I'm using Unity to render it, Here is my full code that generate the objects:

using MidiParser;
using SFB;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using UnityEngine;

public class MidiRead : MonoBehaviour
{
    public GameObject NotePrefeb;
    public float NoteWidth = 1f;
    public float NoteLength = 0.0001f;
    public float NoteDensity = 10000;

    private MidiFile midiFile;
    private string[] FilePath;
    // Start is called before the first frame update
    void Start()
    {
        var extensions = new[] {new ExtensionFilter("MIDI Files:", "mid")};
        FilePath = StandaloneFileBrowser.OpenFilePanel("Open File", "", extensions, false);
        foreach ( string path in FilePath) { midiFile = new MidiFile(path); }

        GameObject NoteParent = GameObject.FindGameObjectWithTag("Notes");

        foreach (var track in midiFile.Tracks)
        {
            
            float[] NoteOnWait = new float[256]; //time = [Note]
            foreach (var midiEvent in track.MidiEvents)
            {
                if (midiEvent.MidiEventType == MidiEventType.MetaEvent)
                {
                    if (midiEvent.MetaEventType == MetaEventType.KeySignature)
                    {
                        Debug.Log("KeySignature: " + midiEvent.Arg1);
                        Debug.Log("SharpsFlats: " + midiEvent.Arg2);
                        Debug.Log("MajorMinor: " + midiEvent.Arg3);
                    }
                    if(midiEvent.MetaEventType == MetaEventType.Tempo)
                    {
                        Debug.Log("Tempo: " + midiEvent.Arg1);
                        Debug.Log("BeatsMinute: " + midiEvent.Arg2);
                        Debug.Log("What?" + midiEvent.Arg3);
                    }
                    if (midiEvent.MetaEventType == MetaEventType.TimeSignature)
                    {
                        Debug.Log("TimeSignature: " + midiEvent.Arg1);
                        Debug.Log("Numerator: " + midiEvent.Arg2);  
                        Debug.Log("Denominator: " + midiEvent.Arg3);
                    }
                }





                if (midiEvent.MidiEventType == MidiEventType.NoteOn)
                {
                    var time = midiEvent.Time / NoteDensity; //Scale the time because Time is too big.
                    var channel = midiEvent.Channel;
                    var note = midiEvent.Note;
                    var velocity = midiEvent.Velocity;
                    NoteOnWait[note] = time;
                    Debug.Log(time);
                    //Debug.Log(note);
                }

                if (midiEvent.MidiEventType == MidiEventType.NoteOff)
                {
                    var time = midiEvent.Time / NoteDensity; //Scale the time because Time is too big.
                    var channel = midiEvent.Channel;
                    var note = midiEvent.Note;
                    var velocity = midiEvent.Velocity;
                    var length = time - NoteOnWait[note];    //NoteOff time - NoteOn time = length


                    //Debug.Log(note);
                    if (NoteOnWait[note] >= 0)
                    {
                        Transform transform = this.transform;
                        transform.position = new Vector3(Map(note, 21, 108, -8.72f, 8.72f), NoteOnWait[note], 1); // X: Map the note from 21~108 to -8.73~8.72,
                        GameObject InstantiateNote = Instantiate(NotePrefeb, transform);// Generate the object    // Y: NoteOn time = where Y starts.
                        InstantiateNote.transform.parent = NoteParent.transform;        // Make the object's parent = this
                        SpriteRenderer spriteRenderer = InstantiateNote.GetComponent<SpriteRenderer>();
                        spriteRenderer.size = new Vector2(NoteWidth, length * 6.666f);  //(Width, Height) Height = (NoteOff time - NoteOn time) / NoteDensity = "length" block high
                   }                                                                    // Multiply 6.666 is because the object prefeb was 0.15 block high
                    else { Debug.Log("NoteOff appear before NoteOn?"); }
                    NoteOnWait[note] = -NoteOnWait[note];
                }
            }

            /*
            foreach (var textEvent in track.TextEvents)
            {
                if (textEvent.TextEventType == TextEventType.Lyric)
                {
                    var time = textEvent.Time;
                    var text = textEvent.Value;
                }
            }*/
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    float Map(float n, float fromLow, float fromHigh, float toLow, float toHigh)
    {
        return (n - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
    }
}

from midi-parser.

davidluzgouveia avatar davidluzgouveia commented on September 24, 2024

Thank you for the sample file, I was able to locate the issue, I'll try to update the repository tomorrow after I fix and run some tests.

from midi-parser.

davidluzgouveia avatar davidluzgouveia commented on September 24, 2024

Actually it was just one line of code... I pushed the fix now, hopefully it works.

from midi-parser.

shinkuan avatar shinkuan commented on September 24, 2024

Yes, it's fixed. Thank you!

from midi-parser.

Related Issues (5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.