Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

converting start/end position in terms of bar #119

Open
shinandrew opened this issue Jan 13, 2017 · 19 comments
Open

converting start/end position in terms of bar #119

shinandrew opened this issue Jan 13, 2017 · 19 comments

Comments

@shinandrew
Copy link

shinandrew commented Jan 13, 2017

Is there a way to represent the start/end position of notes in terms of bar, and vice versa?
(I don't know if "bar" is the right term. I mean a musical length period that is equal to 4 successive notes of quarter lengths.)

@craffel
Copy link
Owner

craffel commented Jan 13, 2017

Not really. The closest you can currently get is using time_to_tick, which will convert time in seconds to tick, which is tangentially related to metrical position. Alternatively, a simple hack would be to call get_beats and get_downbeats, and then assemble the bar/beat position according to the returned values.

I have sometimes thought about making a function which converts from absolute time in seconds to bar/beat position, and vice versa. It was mostly held up by the fact that there was no way to change both the wall-clock and metrical timing of a PrettyMIDI object, but now that has been fixed in #28/#70. I will leave this issue open as a reminder to implement something like this.

@shinandrew
Copy link
Author

Thanx for the reply.

Given the answer, is there a way to check whether a track is monophonic? Or, should I check for notes having the same start position?

@craffel
Copy link
Owner

craffel commented Jan 16, 2017

By monophonic I assume you mean that only at most 1 note is playing at a given point in time (i.e. no chords)? A simple and inefficient way to do that would be

# instrument can be retrieved from the PrettyMIDI.instruments list
monophonic = True
for note1 in instrument.notes:
    for note2 in instrument.notes:
        if note1.start > note2.start and note1.start < note2.end:
            monophonic = False

@bzamecnik
Copy link
Contributor

Test for an instrument track being monophonic - probably not the most efficient way:

def is_mono(instrument):
    return (instrument.get_piano_roll() > 0).sum(axis=0).max() <= 1

Note it depends on get_piano_roll() fs argument (sampling frequency).

@bzamecnik
Copy link
Contributor

As for obtaining the position within the metric grid (measure, beat) actually the MIDI may not contain enough information to precisely determine that. Consider the case with smoothly changing tempo represented just by varying note lengths in ticks, not by tempo change messages. We would have to estimate the tempo curve (instantaneous tempo function + phase of beats and measures) and then perform a mapping to the space of measures. In addition there might be changes in the key signature (eg. 4/4 -> 3/4), so the number of beats per measure may change as well.

@craffel
Copy link
Owner

craffel commented Jul 19, 2017

Consider the case with smoothly changing tempo represented just by varying note lengths in ticks, not by tempo change messages.

I actually have found this to be pretty rare in MIDI files found "in the wild", but it does happen sometimes. That's what the estimate_tempi function is for, at least in part. Estimating the metrical structure is extremely nontrivial though (at least it's easier than for audio, ostensibly :) )... so not within the scope of pretty_midi, I don't think.

@soorejmg
Copy link

Not really. The closest you can currently get is using time_to_tick, which will convert time in seconds to tick, which is tangentially related to metrical position. Alternatively, a simple hack would be to call get_beats and get_downbeats, and then assemble the bar/beat position according to the returned values.

I have sometimes thought about making a function which converts from absolute time in seconds to bar/beat position, and vice versa. It was mostly held up by the fact that there was no way to change both the wall-clock and metrical timing of a PrettyMIDI object, but now that has been fixed in #28/#70. I will leave this issue open as a reminder to implement something like this.

Hi Craffel, is this feature curently available? Could please give a hint on this?

Thanks
Soorej

@soorejmg
Copy link

Hi Craffel,
Basically, I would like to retrieve all time signature bars from a midi file. Is it possible? Please advice.

Thanks
Soorej

@craffel
Copy link
Owner

craffel commented Jun 28, 2020

Hi Craffel, is this feature curently available?

No, it's not a big priority for me, but a pull request would be welcome.

I would like to retrieve all time signature bars from a midi file.

You can use get_downbeats which is not too far off from what (I think) you're asking for.

@soorejmg
Copy link

Hi Craffel, is this feature curently available?

No, it's not a big priority for me, but a pull request would be welcome.

I would like to retrieve all time signature bars from a midi file.

You can use get_downbeats which is not too far off from what (I think) you're asking for.

HI Craffel,
Thanks for this. let me have a try,

Thanks
Soorej

@soorejmg
Copy link

hi Craffel,
image

In this screenshot, is there a way to know whether each note is a quarter note or full note or half note and so on? Any specific method will help?

Thanks
Soorej

@craffel
Copy link
Owner

craffel commented Jun 29, 2020

No, pretty_midi does not support this.

@soorejmg
Copy link

soorejmg commented Jul 1, 2020

Hi Craffel,

Could you help in this. Why is there a estimate_beat_start when there is already a get_beats which returns all the beat location in seconds. A bit unclear, not sure if i am missing something. Please advise

image
Thanks
Soorej

@soorejmg
Copy link

soorejmg commented Jul 1, 2020

Hi Craffel,

For the Piano roll function, it is not clear exactly is the functioality. When i tried, always getting zero value as below. Could you see please.

image

Thanks
Soorej

@craffel
Copy link
Owner

craffel commented Jul 1, 2020

Could you help in this. Why is there a estimate_beat_start when there is already a get_beats which returns all the beat location in seconds. A bit unclear, not sure if i am missing something. Please advise

estimate_beat_start is for MIDI files that have corrupt/missing timing information. You should not need this function for the vast majority of MIDI files.

For the Piano roll function, it is not clear exactly is the functioality. When i tried, always getting zero value as below. Could you see please.

Is midi_data empty? It will produce an empty piano roll for an empty PrettyMIDI object. You can try the example.mid file in the repository root instead.

@soorejmg
Copy link

soorejmg commented Jul 1, 2020

Could you help in this. Why is there a estimate_beat_start when there is already a get_beats which returns all the beat location in seconds. A bit unclear, not sure if i am missing something. Please advise

estimate_beat_start is for MIDI files that have corrupt/missing timing information. You should not need this function for the vast majority of MIDI files.

For the Piano roll function, it is not clear exactly is the functioality. When i tried, always getting zero value as below. Could you see please.

Is midi_data empty? It will produce an empty piano roll for an empty PrettyMIDI object. You can try the example.mid file in the repository root instead.

Hi Craffel,

The midi files where not empty, pfa the ones that i tried with. Just changed the extension as jpg to upload. You could download and rename as midi.

Anger_Abm_145bpm_7 - Copy
Anger - Copy

Thanks
Soorej

@craffel
Copy link
Owner

craffel commented Jul 1, 2020

The files you uploaded do not produce empty piano rolls.

import pretty_midi
pm = pretty_midi.PrettyMIDI("Anger_Abm_145bpm_7 - Copy)
import numpy as np
print(np.all(pm.get_piano_roll() == 0))
print(np.nonzero(pm.get_piano_roll()))

produces

False
(array([37, 37, 37, ..., 87, 87, 87]),
 array([2979, 2980, 2981, ..., 2974, 2975, 2976]))

I'm sorry but I can't continue to provide this kind of support - these GitHub issues are for reporting bugs, not for helping with usage of the library.

@soorejmg
Copy link

soorejmg commented Jul 2, 2020

Hi Craffel,

Thank you so much for these inputs and our sincere apologies for all those silly questions. Just started using the library and getting used with the terminologies and methods. As the domain is music which has multiple terms for the same thing, finding it a bit difficult to understand whether the intentions of certain methods are what we expect to be. Will surely limit our questions are will post everything together.

Thanks
Soorej

@Mannerow
Copy link

Mannerow commented Jul 5, 2022

Test for an instrument track being monophonic - probably not the most efficient way:

def is_mono(instrument):
    return (instrument.get_piano_roll() > 0).sum(axis=0).max() <= 1

Note it depends on get_piano_roll() fs argument (sampling frequency).

Hello. I tried this and it works pretty well for determining mono instruments. Can you shed some light on why this works?

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants