You might want to have a look at RtMidi for comparison:
https://github.com/thestk/rtmidi <https://github.com/thestk/rtmidi>
There are Portaudio and Portmidi, and RtAudio and RtMidi… The later seem to be a result of some lack of responsiveness of the team behind the “portXYs”. I can’t make a judgement at all but I know that projects that still have a choice, tend to prefer the RtXY’s for the community responsiveness, and the codebase is much more recent.
Best
.r.
> On 19. Aug 2020, at 22:39, Bernard Bel <ber...@gm...> wrote:
>
> PS. I haven't checked PortMIDI, but it might handle a message that would cancel all cued events… Being able to stop playing immediately is quite important. This is the only reason why I had suggesyed a separate scheduler.
>
> -------
>
> This sounds very encouraging. Maybe start with PortMIDI (http://portmedia.sourceforge.net/portmidi/ <http://portmedia.sourceforge.net/portmidi/>) since it has been recently fixed for Windows, and you have experience with it. Since the environments (CoreMIDI, MME, ALSA) are different, I suppose that conditional compilation will be necessary…
>
> I guess that the difficulty in picking up accurate timings from the system is the reason why Rick's event scheduler was using assembly language. I had forgotten that time() returns dates with 1 second resolution!
>
> We do have events in chronological order with increasing time-stamps, so the implementation won't affect time-setting algorithms.
>
> Indeed, these "free of charge but…" licenses sound a bit unsane !
>
> Bernard
>
> Anthony Kozar wrote on 19/08/2020 22:12:
>> Bernard,
>>
>> I'm sorry that I didn't reply to this thread earlier to soothe your late night worries! PortMidi DOES appear to support timestamped messages.
>>
>> The GitHub project you looked at is for a PortMidi binding in the Go language. The project for the original C library is here:
>>
>> http://portmedia.sourceforge.net/portmidi/ <http://portmedia.sourceforge.net/portmidi/>
>>
>> The functions for writing MIDI data to a stream are described in the documentation as
>>
>> PmError Pm_WriteShort (PortMidiStream *stream, PmTimestamp when, long msg)
>> Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
>> Messages are delivered in order as received, and timestamps must be non-decreasing. (But timestamps are ignored if the stream was opened with latency = 0.)
>>
>> PmError Pm_WriteSysEx (PortMidiStream *stream, PmTimestamp when, unsigned char *msg)
>> Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
>>
>> I also looked at the source code which has a little more information about the latency parameter. If we set a positive latency of at least 1 ms, then the timestamps will be honored and PortMidi will use the system's native Midi scheduler if there is one. (CoreMIDI has a very accurate scheduler with times measured in nanoseconds!) Only with a latency of 0 would the timestamps be ignored. So, I think we can either let the system or PortMidi schedule the events or do it ourselves.
>>
>> I think it will be easier for getting started to send timestamped messages and let the native libraries on macOS/Windows/Linux do the scheduling if they support that. On today's multitasking OSes it is much harder, I think, to guarantee that a program can accurately perform timed tasks without resorting to system-specific timer calls and possibly a multithreaded architecture. IIRC, functions like sleep() are not guaranteed to return in time and the function time() has only 1 second precision. For the CoreMIDI driver, I used functions from the CoreAudio library to get very precise times from the system clock and convert them to milliseconds to use for BP2's ClockZero reference time.
>>
>> That said, I am definitely open to other options for a cross-platform MIDI library. I was just aware of PortMidi because it is used by Csound and some other software I've used. But there was a very recent discussion on the Csound dev list about how PortMidi had not been updated in a very long time and was causing some issues with their Windows build. The problem appears to have been solved by contacting the PortMidi developers and they patched the source code repository this month, IIRC. But if there is a better supported, open-source library out there, I think we should strongly consider it.
>>
>> Although I have heard some good "buzz" about JUCE in the past, I didn't realize that it is not open source. I think the JUCE licensing model would definitely be a deterrent to other developers getting involved in BP development or reusing BP in their own projects.
>>
>> Anthony
>>
>> P.S. Rick Taube has made some great music software tools over the years (primarily Common Music which I used to use). Even though the source code for his software was available to everyone, it was not always possible for other individuals to redistribute his software with modifications because he used tools that required expensive redistribution licenses (~$2000-2500 IIRC for Macintosh Common Lisp). He would purchase those distribution licenses so that anyone could use his software (I assume with grant money). But it was disappointing to me that I couldn't distribute Mac OS 9 builds of software made with MCL after he (and others) stopped even though I purchased a (user-level) license for MCL.
>>
>>
>> On 8/19/20, 2:01 PM, Bernard Bel wrote:
>>> I thought about all this again last night…
>>>
>>> The argument that PortMIDI only accepting real-time MIDI messages rather
>>> than time-stamped MIDI events would generate a cumulation of errors does
>>> not hold! It is easy to schedule events according to absolute time
>>> (starting from a defined zero date).
>>>
>>> The following is (approximate) code for playing a 2-second C major chord
>>> starting after 1 second.
>>>
>>> time_zero = time(); // milliseconds
>>>
>>> next_event_date = 1000;
>>> while(time() < (time_zero + next_event_date)) {
>>> $result = ListenMIDI();
>>> if($result == STOP) break;
>>> }
>>>
>>> out.WriteShort(0x90, 60, 100)
>>> out.WriteShort(0x90, 64, 100)
>>> out.WriteShort(0x90, 67, 100)
>>>
>>> next_event_date = 2000;
>>> while(time() < (time_zero + next_event_date)) {
>>> $result = ListenMIDI();
>>> if($result == STOP) break;
>>> }
>>>
>>> out.WriteShort(0x80, 60, 100)
>>> out.WriteShort(0x80, 64, 100)
>>> out.WriteShort(0x80, 67, 100)
>>>
>>> Variables "next_event_date" are the time stamps that we used to imbed
>>> into MIDI events. We could even count in microseconds at the same cost. ;-)
>>>
>>> ListenMIDI() is trying to capture an incoming event (or a keyboard
>>> stroke) that would instruct the console to modify some settings or stop
>>> playing immediately. (It is already implemented.)
>>>
>>> Frankly I don't understand why a complex scheduler was required when it
>>> looks so simple. Maybe there is a hidden problem that I haven't figured out!
>>>
>>> If you create a very simple C program, we can check this procedure and
>>> then implement it in the console. The only difficult problem, which
>>> PortMIDI will solve, is the connection to MIDI in/out devices…
>>>
>>> I also felt reluctant to use a framework like JUCE because it has a
>>> license that might prevent the reuse of BP3 in other (possibly
>>> commercial) environments.
>>>
>>> Bernard
>>>
>>> -----------
>>>
>>> There is another advantage in creating a "merry-go-round" MIDI event
>>> loop sending events at their proper time instead of streaming them in
>>> advance with time-stamps as we had done with OMS.
>>>
>>> In this setup, events can be modified or deleted at any time before they
>>> are played. In a time-stamped stream you cannot modify events once they
>>> have been queued to the MIDI driver.
>>>
>>> For instance, the user may program an incoming event (a MIDI NoteOn, a
>>> stroke on the keyboard) to stop playing immediately and delete all
>>> pending events, or keep them on a pause. This will evidently happen in
>>> real-time music production, and even more if several machines are
>>> interacting in a cooperative manner.
>>>
>>> So, I suggest that we look for (or design) an algorithm able to schedule
>>> events in real time… Then PortMIDI would be a workable option!
>>>
>>> Bernard Bel
>>>
>>> --------------
>>>
>>> I had a quick look at PortMIDI which is one of the suggested tracks to
>>> solve the problem of real-time MIDI output/input:
>>>
>>> https://github.com/rakyll/portmidi <https://github.com/rakyll/portmidi>
>>>
>>> The input (listening to events) is probably easy to implement as
>>> previously done in the ListenMIDI() loop. But the ouput seems more
>>> problematic. Their example for playing a C major chord for 2 seconds is:
>>>
>>> // note on events to play C major chord
>>> out.WriteShort(0x90, 60, 100)
>>> out.WriteShort(0x90, 64, 100)
>>> out.WriteShort(0x90, 67, 100)
>>>
>>> // notes will be sustained for 2 seconds
>>> time.Sleep(2 * time.Second)
>>>
>>> // note off events
>>> out.WriteShort(0x80, 60, 100)
>>> out.WriteShort(0x80, 64, 100)
>>> out.WriteShort(0x80, 67, 100)
>>>
>>> This means that it would take MIDI events without a time-stamp, and all
>>> scheduling would be managed by time.Sleep().
>>>
>>> Even though time.Sleep() might accept very accurate time intervals, the
>>> cumulation of intervals over thousands of events is likely to generate
>>> imprecision.
>>>
>>> In the current layout (as I remember it) we send time-stamped MIDI
>>> events containing "absolute" timings (from a unique "zero" point) which
>>> makes it possible to maintain time accuracy with 1 millisecond whatever
>>> the number of events.
>>>
>>> Maybe this has already been discussed (and solved) by developers using
>>> PortMIDI…
>>>
>>> Before OMS I was using a loop (written in assembly language) to schedule
>>> events accurately as it was not yet possible to time-stamp them. I am
>>> not sure I still have the code which anyway is totally obsolete since it
>>> was for MacOS 9. Nonetheless, creating that kind of loop would be a
>>> manner of using PortMIDI without resorting to time.Sleep().
>>>
>>> I remember using the image of a merry-go-round to visualize this event
>>> loop; but this may not be of great help! ;-)
>>>
>>> An important detail is that BP2 (in MacOS 9 + OMS) did send events in
>>> their chronological order even though time-stamping did not make it
>>> compulsory. This feature might turn out useful when implementing a new
>>> driver…
>>>
>>> A practical way of approaching this might be to write a very simple C
>>> program whose sole work is to broadcast a couple of MIDI events, then
>>> listen to capture an incoming event.
>>>
>>> Bernard Bel
>>
>>
>> _______________________________________________
>> bolprocessor-devel mailing list
>> bol...@li... <mailto:bol...@li...>
>> https://lists.sourceforge.net/lists/listinfo/bolprocessor-devel <https://lists.sourceforge.net/lists/listinfo/bolprocessor-devel>
>
> _______________________________________________
> bolprocessor-devel mailing list
> bol...@li...
> https://lists.sourceforge.net/lists/listinfo/bolprocessor-devel
|