<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Well, there is python-midi, which is stable enough:<div><a href="https://github.com/vishnubob/python-midi/">https://github.com/vishnubob/python-midi/</a><br></div><div><br></div><div>You can easily create a script that automatically "shifts" the timing of events by decreasing the tick of the first event.<br>By "easily" I imply some basic rules:</div><div>- all events which have to be shifted must be on the same midi track<br></div><div>- the first Note event in any of those tracks should not be at the very beginning of the file</div><div>- tempo changes, if any, should not be too big</div><div><br></div><div>Of course, it's possible to do the same even with these limitations, but it will be much more difficult to implement it in the right way.</div><div><br></div><div>Timing in midi files works with "ticks" or "pulses", and each file has its own resolution, which represents the tick resolution per beat, or the smallest possible quantization: if a midi file has a resolution equal to 128 it means that the smallest possible division is a 128th of a quarter note.</div><div><br></div><div>The python-midi module treats midi files as nested lists. The main object, representing the midi file read (or to be written), is a Pattern, which is a list of Tracks, which in turn is a list of MidiEvents.</div><div><br></div><div>A very basic example, assuming you know the exact structure of your midi file and you want to shift the second track:</div><div><br></div><div><font face="monospace, monospace">import midi</font></div><div><font face="monospace, monospace">pattern = midi.read_midifile('myfile.mid')</font></div><div><font face="monospace, monospace">strings = pattern[1]</font></div><div><font face="monospace, monospace">#let's see what's the next event with a positive relative tick<br></font></div><div><font face="monospace, monospace">eventId = 0</font></div><div><font face="monospace, monospace">event = strings[eventId]</font></div><div><font face="monospace, monospace">while not event.tick:</font></div><div><font face="monospace, monospace"> eventId += 1</font></div><div><font face="monospace, monospace"> event = strings[eventId]</font></div><div><font face="monospace, monospace">#ensure that the resulting tick is >= 0</font></div><div><font face="monospace, monospace">firstEvent.tick = max(0, firstEvent.tick - 150)</font></div><div><font face="monospace, monospace">midi.write_midifile('newfile.mid', pattern)</font></div><div><br></div><div>Sometimes midi files contain an "invisible" track which includes some metadata; if you know the track name (and there are no duplicate names), you can find it like this:</div><div><br></div><div><font face="monospace, monospace">import midi</font></div><div><font face="monospace, monospace">pattern = midi.read_midifile('myfile.mid')</font></div><div><font face="monospace, monospace">#the TrackName event _should_ be the first event in the track...</font></div><div><font face="monospace, monospace">for track in pattern:</font></div><div><font face="monospace, monospace"> for eventId, event in enumerate(track):</font></div><div><font face="monospace, monospace"> if isinstance(event, midi.TrackNameEvent) and event.text == 'Strings':</font></div><div><font face="monospace, monospace"> break</font></div><div><span style="font-family:monospace,monospace">eventId += 1</span><br></div><div><font face="monospace, monospace">event = track[eventId]<br></font></div><div><font face="monospace, monospace">while not event.tick:</font></div><div><font face="monospace, monospace"> eventId += 1</font></div><div><font face="monospace, monospace"> event = track[eventId]</font></div><div><font face="monospace, monospace">event.tick = max(0, event.tick - 150)</font></div><div><font face="monospace, monospace">midi.write_midifile('newfile.mid', pattern)</font><br></div><div></div><div></div><div><br></div><div>These are very simple examples, with no error checks at all.<br></div><div>Also, the 150 subtraction is arbitrary, and it should be computed according to the tempo and the tick resolution, which is accessible using <font face="monospace, monospace">pattern.resolution</font>; supposing that your file has a resolution of 600 ticks per beat, the above examples will anticipate every event by a 16th, or 0.125 seconds if the tempo is set to 120bpm.<br>Once you've found out what's the preferred anticipation in seconds of your patch, you could compute the right timing in the script also: Tempo events are usually in the first track, so just cycle through it until you find a SetTempoEvent, and compute the "delta tick" like this:</div><div><br></div><div><font face="monospace, monospace">deltaSecs = 0.125</font></div><div><font face="monospace, monospace">deltaTick = int(deltaSecs * pattern.resolution * tempoEvent.bpm / 60.)</font></div><div><font face="monospace, monospace">[...]</font></div><div><font face="monospace, monospace">firstEvent.tick</font><span style="font-family:monospace,monospace"> </span><span style="font-family:monospace,monospace">= max(0, event.tick - deltaTick)</span></div><div><br></div><div>I hope this helps!</div><div><br></div><div>MaurizioB</div><div><br></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">2018-08-29 22:30 GMT+02:00 Francesco Ariis <span dir="ltr"><<a href="mailto:fa-ml@ariis.it" target="_blank">fa-ml@ariis.it</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello LAU,<br>
lately I have been playing with ABC notation [1].<br>
ABC outputs to postscript/PDF and MIDI (a good output), but there<br>
some things I would like to change in automatic fashion. Example:<br>
anticipate the attack on some channels (string).<br>
Is there a command line Linux utility to mess with midi files,<br>
similar to what ImageMagick is for images?<br>
I know plenty of libraries in many programming languages, but before<br>
diving into those I would like not to reinvent the wheel.<br>
<br>
[1] <a href="http://trillian.mit.edu/~jc/music/abc/doc/ABCtut_Intro.html" rel="noreferrer" target="_blank">http://trillian.mit.edu/~jc/<wbr>music/abc/doc/ABCtut_Intro.<wbr>html</a><br>
______________________________<wbr>_________________<br>
Linux-audio-user mailing list<br>
<a href="mailto:Linux-audio-user@lists.linuxaudio.org">Linux-audio-user@lists.<wbr>linuxaudio.org</a><br>
<a href="https://lists.linuxaudio.org/listinfo/linux-audio-user" rel="noreferrer" target="_blank">https://lists.linuxaudio.org/<wbr>listinfo/linux-audio-user</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div>
</div>