Dear Anthony,
This is a partial answer to your message.
Today I completed the management of MIDI files on the Timbase and
Prototype pages. At last I understand the timing parameters.
The important ones are "division" and "tempo".
"Tempo" alone is sufficient to designate the speed of the item. It is
the duration of a quarternote (i.e. 1 beat) in microseconds. In BP the
speed is fixed by Pclock and Qclock, namely how many beats (Pclock) in
how many seconds (Qclock). We use an integer ratio which yields perfect
accuracy.
So, by default, if mm = 60 beats per minute, Pclock = Qclock = 1. The
period of the clock is 1 second and tempo = 1000000 (µs).
If mm = 120 bpm, Pclock = 2 and Qclock = 1. The period of the clock is
0.5 second and tempo = 500000 (µs).
I think it is good to set this parameter according to the current Pclock
and Qclock.
In "-gr.Visser.Waves", Harm did something unusual. He used the default
mm = 60 bpm, but since the piece was too fast he wrote _tempo(0.8) at
the beginning to slow it down. Yet, this is a "performance parameter"
that we can't guess only from the MIDI file. He should have removed this
parameter and set Pclock = 8, Qclock = 10. Or simplify: Pclock = 4,
Qclock = 5. Which yields tempo = 5/4 * 1000000 = 1250000.
Now, about "division"…
MIDI files contain time signatures which are number of "ticks".
"Division" is the number of ticks in a quarternote. So, the duration of
a tick is tempo/division (µs). We have complete freedom to decide on
that duration as it won't change the playback. However, in BP I always
used milliseconds for time signatures - as they are the ones needed for
real-time MIDI streams.
Therefore, tempo/division = 1000. Once you know the tempo, calculate
division = tempo / 1000 and assign milliseconds to time signatures. This
will work perfectly.
On the PHP interface I fix MIDI files adding Meta track names. I am no
longer sure, it seems that missing track names was crashing a process.
The thing I am sure is that "Meta TrkEnd" is compulsory before TrkEnd,
and its time signature must be the same as the last event.
I remember that in BP2 I had set up a slow volume fading out at the end
of the piece because ending suddenly would produce unwanted noise on the
D50. But this might be related with the missing code at the end! You can
try to get rid of it. Playing the MIDIfile on a syth piano with
resonance will indicate whether this is required or not.
I don't think it would make sense to include a TimeSig event in the
first track. By default I insert "0 TimeSig 4/4 24 8" though I don't
know what "24" and "8" stand for. This might be used for communication
with a rhythm box.
The typical beginning of a MIDI file (in MF2T notation) is:
MFile 1 2 1000
MTrk
0 Meta TrkName "header"
0 TimeSig 1/4 24 8
0 Tempo 1000000
0 KeySig 0 major
0 Meta TrkEnd
TrkEnd
MTrk
0 Meta TrkName "track_1"
0 On ch=1 n=48 v=50
890 On ch=1 n=54 v=50
1780 On ch=1 n=48 v=0
1780 On ch=1 n=61 v=50
...
Here, "1780" is a time signature in milliseconds since division = 1000 and tempo = 1000000.
So, you see that I use one track only for the settings, among which TimeSig and KeySig are probably unnecessary. But some machines might require them even if they don't mean anything…
Type-0 files? No use, I believe. You can produce a type-1 file even with a single track. If you follow the idea of a "header" track then you will get at least 2 tracks.
I am not sure that we still can deal with producing MIDI files in the "Non-stop improvize" mode. It is supposed not to end until the machine receives a "stop" signal: key stroke or MIDI event (or Apple event in BP2). We could only tell the console to produce x items and store each one in a separate file. Or maybe "pipe" each file to a synthesizer and delete it afterwards — which would be a manner of doing almost real-time production!
Finally, I might have replied all questions. ;-)
Bernard
Anthony Kozar wrote on 14/08/2020 22:31:
> Thanks! This is all timely information since I have been working on
> rewriting Midi file output in BP Console over the past two weeks.
> I've ended up making many more changes than were strictly necessary.
> Some will hopefully make the code more portable. Some involve just
> refactoring duplicated code into separate functions, etc. There are
> also two functions that I decided to rewrite from scratch because the
> previous code appeared to have been copied from that MIDI file
> specification document that you sent me, Bernard.
>
> Unfortunately, I haven't finished this task yet because of various
> other things that have come up.
>
> Comments below...
>
> On 8/13/20, 5:20 AM, Bernard Bel wrote:
>> More on this topic:
>>
>> I was wrong regarding "division": in this MIDI file, division = 1000 is
>> the correct value, provided that we keep the information contained in
>> the first track, namely "TimeSig" and "Tempo".
>
> Yes, I have noticed that BP2 always writes a division of 1000,
> presumably for millisecond accuracy?
>
>> The content of the MIDI file is attached in MF2T text format to make
>> things clear.
>>
>> The original content was incorrect and MIDIjs refused to play it. It
>> became correct after adding these metadata:
>>
>> 0 Meta TrkName "imported_1"
>> ...
>> 0 Meta TrkName "imported_2"
>> ...
>> 171250 Meta TrkEnd
> >
>> Therefore, tracks require (arbitrary) names and a "Meta TrkEnd" should
>> be placed just before each "TrkEnd" instruction. At least, these are
>> requirements for MIDIclass.php to produce a MIDI file accepted by
>> MIDIjs.
>
> The specification that you sent does not say that the Meta TrkName
> events are required. It just says "Sequence Number and
> Sequence/Track Name events, if present, must appear at time 0."
> However, it should be easy to add them for compatibility if desired.
>
> The "Meta TrkEnd" is required and BP2.9.8 should write it. But the
> TrkEnd for the final track appears not to be written until the file is
> closed. Therefore, I suspect that you may have copied the Midi file
> before BP2 closed it. This is related to the problem reported by Rob
> Moore. Perhaps it would be better to finish writing the file and
> close it at the end of performance unless BP is in a mode where
> producing multiple items is expected? Alternatively, the file could
> always be closed at the end of performance and reopened and extended
> if necessary.
>
>> When trying to import it to a sound-object prototype I got an error in
>> MIDIclass.php indicating that the last event (a NoteOff) had been lost.
>> The file was imported anyway but the last event was missing. We do get
>> the last NoteOn timed 171250 ms but we miss its NoteOff around 180000
>> ms.
>
> This is probably related to the same problem above. The last normal
> Midi event also does not get written until the file is closed.
>
> There are other related problems that I have discovered too. If
> "Non-stop improvise" is on with the option to write each item to a new
> MIDI file after it is performed then the track duration is equal to
> the total elapsed time of the performance _including_ the time it
> takes the user to enter a file name and click "Save"! It also appears
> that that BP2 may be writing "0" for the time of the "Meta TrkEnd"
> event when it should correspond to the track duration.
>
> If it sounds like the second issue contradicts the first, I think it
> because BP2 writes a lot of volume controller events at the end of
> each track to "fade out" the performance and that lengthens the track
> if it doesn't occur immediately. Is there a good reason for this fade
> out? I can imagine it being confusing if the MIDI file is played back
> on a synth and then the user tries to play notes on that synth outside
> of BP2 and hears no sound as a result.
>
>> In addition, the "division" found by MIDIclass is "1000" yielding a
>> faster playback. It should be set to "480" for a reason I still don't
>> understand…
>
> If I am remembering correctly, I think 480 is a common division of the
> quarter note for MIDI sequencers. I always thought it strange too,
> but if you factor 480 you get 2*2*2*2*2*3*5 which is a clue, I think.
> This division allows quarter notes to be accurately subdivided into
> 128th notes or any triplet or quintuplet division of the power-of-2
> note durations. So, 480 divisions could be more accurate for some
> music than the 1000 divisions BP2 is using.
>
>> Problems are identical when exporting type 0 and type 1 files. We should
>> avoid type 0 anyway, even though BP always produces single-track files.
>
> What is the reason for avoiding type 0?
>
>> This trace might be helpful for the design of MIDIfile export on the
>> console…
>
> Yes, thank you for delving into these issues! I'll keep all of this
> in mind as I work on the code.
>
> Anthony
|