I'm working on a MIDI step sequencer. I'm using the timer device and a usual Wait() loop. But sometimes the delay is too long and the playback has a small glitch even if I'll set the task priority to 2-10. Currently I'm using the UNIT_MICROHZ because it gave me the best result. I was trying to adjust the delay value depending on how long it took between IO calls but that didn't help good enough eventually.
Can I use interrupts somehow ? And if so then how ?
I tried to use realtime library also but didn't get it to do anything.
So what's the best way doing this kind of looping on AmigaOS ?
I get good timing when playing back MIDI files, I suspect the changes I made might help.
MIDI files are stored as a sequence of MIDI events, and in between each one is the delay until the next event plays. My first playback program was very simple, keep sending MIDI until you get a non-zero delay, then wait for that long. Timing was terrible.
Doing it that way does not account for delays due to multitasking, and it also does not account for the time required to assemble and send your MIDI events.. eventually all the little errors add up until the timing just sounds sloppy.
What I did was to convert every event time into an offset from the song start. Then on playback, send all events with a timestamp earlier or equal to "now", then sleep until Song_Start_Time + offset to next event.
This way you are following the clock, instead of expecting the clock to follow you.
I have found excellent playback timing, even at a task priority of zero.
I was already using a fixed delay with the timer.device and using a counter to check when it's time to play a next note. But my mistake was to increase the counter by one every time. I fixed timing increasing the counter by a corrected value counting how long it actually took between the timer signals. Now it plays perfectly.
Thanks, for advice !
Can I send MIDI messages between two apps running on the same computer ? And how can I make my software being listed as a MIDI "device" by camd library ?
I use CAMD for inter-task comms all the time. Most MIDI messages are three bytes or less, but System Exclusive messages can be longer, within reason.
All messages are passed between named ports. there are very few rules on how the names are formatted. You MUST use unique names, so it may be wise to check if a name is already in use, and add an (increasing) digit to follow or make it unique by some other means.
As long as you can format it as "legal" MIDI messages, have fun!.
Remember a few details:
If multiple streams are sent to the same destination, they will be simply mixed together at reception. the receiver CAN tell from where each message came if it cares to look.
You can also send multiple streams FROM a given port, each destination gets a copy of the messages.
So mixing (merging) is easy, as is multicasting.
To make your program appear as a port... there is nothing to do. Just give it a name that (hopefully) helps people understand what it is. All named ports (that aren't specifically hidden) will appear in the port requester.
As an example, the USB MIDI driver is not really a "driver", it's a simple program.
There's no difference betweeen a driver and a program, they all meet in the same place, and all interconnect by the same means.
Say I wanted to merge MIDI messages from: My Behringer "BCR2000" control surface, My "VMeter" volume touch slider, and the big knob on the front of my audio mixer... I just create a named "meeting place", which I call "mix".
MidiThru is a simple patch cord with two required arguments, from and to..
MidiThru VMeter.in.0 mix
MidiThru BCR2000.in.0 mix
MidiThru MBMixer.in mix
Now all three are combined, at the (imaginary) port called "mix"
Let's connect the output to all three as well:
MidiThru mix VMeter.out.0
MidiThru mix MBMixer
MidiThru mix BCR2000
OK, so if ANY of those controls changes volume, the mixer (MBMix) will adjust accordingly, and ALL THREE of the control surfaces will move together. Like magic!
Bars&Pipes can simply send volume change messages to "mix" and it will control the audio mixer, and all three devices will move together in sync.
This example is exactly what I have running 24/7. Simple and reliable.
More questions? Feel free to ask here, or you can email me personally, however you prefer.
I am always happy to get camd working for different applications.
Maybe I can be more clear..
To create a link between two programs. both open camd.library, and make a node using mynode = ICamd->CreateMidi(). Now to communicate, just create a link to a named location. ICamd->AddMidiLink(mynode, MLTYPE_Sender, MLINK_Location, "uniquename", TAG_END). THe second program does the same except it uses it's own node, and MLTYPE_Receiver.
Now every MIDI event sent by program A will be received by program B. Also, any other programs that go looking for places to connect will see "uniquename" as an option. They can send to it or receive from it.
If I created more questions then please ask!
Thanks a lot !
My mistake was I was listing clusters only but not cluster links. Then I was wondering how do I create my own cluster. But it's enough to add a new midi link and it's automatically "clustered". I got everything working now.