Comments (7)
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.
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.
I add the time value next to the objects
from midi-parser.
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.
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.
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.
Actually it was just one line of code... I pushed the fix now, hopefully it works.
from midi-parser.
Yes, it's fixed. Thank you!
from midi-parser.
Related Issues (5)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from midi-parser.