Maestro
Chris (121) 472 posts |
I’ve uploaded a revised version of Maestro that uses updated sprites. These are based on Richard Hallas’ PMS font, used with permission. I’d be interested in views on how they look, and if there are any glitches in the layout as a result. Some points to note: At this stage I haven’t looked into any of Maestro’s other ‘quirks’. Looking at the file format, I think some of these issues are solvable, so I might take a look at those in due course. Anyway, comments welcome. |
Chris (121) 472 posts |
Maestro’s had some fairly extensive changes to its interface, which are now in CVS. As there’s a lot of code changes, there are likely to be glitches that slipped through – if people could give it a whirl, that would be great. |
Rick Murray (539) 13850 posts |
I meant to email you about this… Meant to… Famous last words, huh? <facepalm> Suffice to say, it now looks much better. I’m pleased that obnoxious giant menu has been tamed. I found an itty bitty glitch – if the MIDI channel assignments, the available channels are listed as “MIDI channel 1” to “MIDI channel 8”, with the corresponding menu option ticked. Something that might make a big difference to MIDI support is the ability to associate a voice with a channel. I think, by default, everything ends up as a standard piano, however on GM compliant devices, it is possible to select from something like 100 different voices (strings, guitar, etc). Are there any plans to add this in the future? |
Rick Murray (539) 13850 posts |
In your examinations of Maestro, have you spotted any potential flaws in the note playback mechanism? The playback of a complex piece is still very…eccentric on RISC OS 5. Here is an example Maestro file (Erasure’s “A Little Respect”) and a recording of the first part I just made with my phone. It’s an m4a file. http://heyrick.ddns.net/files/maestest.zip It starts off okay, but as there are more notes to be played it…just goes a bit crazy. There’s no logical reason for a 900MHz machine polling over a thousand times a second failing to be able to play eight notes at the right time. There must be some sort of implementation issue…? PS: You really don’t want to listen to this. Trust me, you don’t. ;-) |
Chris (121) 472 posts |
Thanks. I’ll get that fixed.
Yes, that would be good to have. The Maestro file format has a (currently unimplemented) block to specify the MIDI channel for each internal voice. When I get around to implementing this, I’ll see if it’s possible to extend the spec to also include a GM name (and possibly other useful info).
I suspect there’s lots :) I’ve not looked at playback at all yet. Once this version is stable, my intentions are to fix the worst glitches in the redraw/typesetting code, followed by implementing the various bits of the file spec that have never been got round to. After that, and taking a deep breath, I can look into at the playback code. I’ve no idea at present whether what you’ve observed is an issue with Maestro, or with the sound system more generally. |
Dave Higton (1515) 3534 posts |
This is a good time to remind all concerned that a centisecond timebase for playback is not good enough. (I’m sure it isn’t the only problem at present, but let’s find and fix all the contibutions.) I remember disassembling the code for an Acorn MIDI interface back in the late 1980s, and realising that it used a millisecond timer. Why would they have gone to the trouble of setting up and using another timer when the centisecond timer was there and pervaded the whole OS? Answer: because centiseconds are not good enough for MIDI recording and playback. You need finer resolution. It just happens that a millisecond timer fits nicely with USB frames. That’s a nice bonus when considering playback to (and recording from) external devices. The most fundamental thing we’re dealing with here is that MIDI requires hard real time performance. Real time does not sit at all well with desktop operating systems. Nor does the thought process sit well with people who have only ever programmed a desktop OS. So I’ve highlighted two things that need to be addressed: 1) Hard real time operation; 2) Millisecond resolution. |
Dave Higton (1515) 3534 posts |
Having set out a couple of the problems: what possible solutions can we come up with? I think we need to have a real time subsystem and some interfaces. The real time system needs to run regularly (in the proper sense of the word), without fail, and frequently enough. That means it needs to be interrupt-driven from a timer faster than centiseconds (for MIDI, millisecond seems a good first choice). It needs to have frame numbers that repeat over a long enough time; 32 bits would appear to be enough. It needs to be able to insert audio into playback buffers according to a timestamp. It needs to be able to put USB transfers into the queue according to a timestamp. For MIDI recording, it needs to be able to extract USB transfers from buffers and time-tag them for collection by a non-real-time entity. More ideas? Better ideas? |
Rick Murray (539) 13850 posts |
I think the GM assignments are standardised, so perhaps a number would suffice? Unfortunately for additional voices, there are various competing “standards”. My keyboard (Yamaha) supports XGLite which, from memory, uses an additional command to select voice bank, then the voice desired in the normal way (with the bank selecting if GM or XG). I think Roland has a similar but different protocol… Then there’s General MIDI 2 that is less supported and was intended to resolve the differences in the previous mentioned extensions. If I can make a suggestion, if you’re using a word for the MIDI voice, define the lower byte to be the voice (in whatever manner you want) and specify the other three bytes as “for expansion”. You can look to Roland/XG support at some future time, and just work with GM1 for now – that’ll be a huge improvement over what Maestro currently does. Also, you should probably disallow the user setting MIDI channel 10. The above Wiki document states: Notes recorded on channel 10 always produce percussion sounds when transmitted to a keyboard or synth module which uses the GM standard. Each of the 128 different possible note numbers correlate to a unique percussive instrument, but the sound’s pitch is not relative to the note number.
We don’t have much choice here. Pretty much the entirety of RISC OS is based around a centisecond ticker. Maestro uses the beat counter; and apparently the scheduler is supposed to be called every centisecond (docs for Sound_Configure) though it looks like RO5 may be using RTSupport?
Remember we’re talking about machines running at 8MHz – probably why they also added a SWI to return an internal address to completely bypass the SWI handling mechanism.
And for playing music written in Maestro? Remember, the ticker is 100 ticks per second. Not even death metal gets anywhere near that sort of tempo. The typical fastest music (if you can call it that) is fast speedcore and extracore which can run up to 1000bpm. That’s six ticker events per beat. So while I would agree that millisecond timing is useful to tag which order notes arrived (if within the same centisecond tick), I don’t feel that 1/100th of a second events are an impediment to playback. Hell, the sound of “mains hum” is half that frequency…
There, fixed that for you.
RTSupport? Personally, I would support the implementation of something like FastTickerV that runs to a millisecond clock, but otherwise behaves like TickerV. This should be available as an event (standalone, not jumbled into EventV, decoding takes time), as well as FastCallAfter and FastCallEvery style interfaces, plus OS_ReadFastTime to get the current value of the ticker. A brief look at the HAL, it looks like this could be achieved by cranking up the timer to fire an IRQ ten times faster. This will call into a new Timer_FastDevice (1000Hz), while also decrementing a private counter. When that private counter is zero, reset it to 9 and then call the current Timer_Device (100Hz). That’s my idea… As for all of this:
The FastTickerV will be an IRQ mode routine just like TickerV, so it’ll be code hanging off that just as it would for TickerV (or a callback) now. As such, FastTick doesn’t need to be capable of doing anything other than calling code that can do the necessary. |
Dave Higton (1515) 3534 posts |
You’re missing the point, Rick. Maestro is a very crude player. We need to sort out something for the general case. Look at spreading a chord. Maestro can’t do it, but, if RISC OS is to be a good enough general purpose MIDI recorder/player, it needs to handle human input. If a musician spreads a chord, the events come very close together. If you quantise them to a resolution of 10ms, it sounds ragged. If you quantise them to a resolution of 1ms, it’s OK. I’ve been reminded of these considerations by talking to one of the guys who comes to many of the RONWUG meetings. He’s struggling to revive A7000’s and such machines, specifically for MIDI use. I asked him why he doesn’t use a Raspberry Pi. It’s because the USB MIDI performance is not good enough. I’ll remind you of why the original Archimedes-era MIDI interfaces used a 1ms timer, when using the 10ms timer would have been much easier. 10ms is not good enough. It’s a simple statement of fact. Maestro, because of its crudity, is a special case where we might get away with 10ms. But that’s the best that can be said. It doesn’t cover the general case well enough for any serious use, even serious amateur use. |
Dave Higton (1515) 3534 posts |
If we can come up with something that’s good enough for general use, it will also be good enough for use with Maestro. |
Rick Murray (539) 13850 posts |
…hence my FastTickerV suggestion. There’s little point debating how to get MIDI at millisecond resolution until RISC OS has a mechanism for doing things at millisecond resolution…
I’m setting up events to run off TickerV so the best it does is 100Hz, with the fast clock being faked. I’ll look, in the future, to pulling data directly from buffers and bypassing the file handling routines (to remove callback latency), but I don’t have plans to do this until RISC OS is capable of dealing with timed events faster than centisecond resolution. I think it’s also worth pointing out that my primary design goal with USBMIDI was “can I talk to my keyboard?” and the only reason I cloned the API of the old Acorn MIDI module was because the only music software I have is Maestro, and Maestro speaks Acorn MIDI – sort of (that’s why it works with how Maestro works, but may not work with other things, specifically things that schedule ahead of time). BTW, that implies it’s not only because the MIDI interfacing isn’t good enough, it’s also because there’s a lack of available software. In the 26 bit realm there are options. In the 32 bit realm, not so much. |
Andrew Conroy (370) 740 posts |
There was a discussion regarding making a higher resolution timer generally available here but I’m not sure what became if the idea. |
Dave Higton (1515) 3534 posts |
My BBxM claims to have 7 HAL timers. |
Dave Higton (1515) 3534 posts |
That’s like saying we can’t start to do anything until we’ve got everything in place. Chicken and egg. OK, let’s construct some DNA… |
Dave Higton (1515) 3534 posts |
… and I can get the device number (IRQ number) for all of them. e: … and they all claim to run at 13000000 ticks per second. |
Dave Higton (1515) 3534 posts |
Thanks, Andrew. I’ve posted to it. |
Dave Higton (1515) 3534 posts |
There is another question to ask: is it reasonably possible to derive a 1kHz tick from USB, where a machine has a USB host? Since the USB frames and HAL timers are derived from different clock sources, they will never run at exactly the same frequency. |
Colin (478) 2433 posts |
No. You only get interrupts from a ehci driver on completion of some event like transfer complete so interrupts from USB are very erratic. |
Dave Higton (1515) 3534 posts |
Well, I’ve got a dead simple module running, counting ticks at 1kHz. I can’t actiually check that it’s 1kHz, but it certainly looks about right. I’ll maybe test it later. OK, what should it do? Would there be any use in providing a function to, say, CallAtTick, where a caller can register to have some code called at a particular tick number? Call with the required tick number, the address of the code to be called, and a word that would be passed back to the caller? This would allow code to queue events to take place at specific millisecond times. It should be possible to get audio fragments (notes) into the sound system, or get USB messages into the USB transmission system. Although it’s no good just putting the message into a buffer to be processed on a callback; it would have to be handled directly and immediately by the USB system, to be of any use. |
Rick Murray (539) 13850 posts |
Surely if you’re just moving data from this buffer to that buffer, it can be done (with any minimal processing required) just as would be done periodically upon TickerV or via OS_CallEvery/CallAfter? In the case of MIDI, it should suffice to copy the MIDI frame bytes to the destination buffer and attach a timestamp. This means that while there will be latency between the USB device receiving the data and the foreground application dealing with it (completely unavoidable), the important part will have been dealt with – the timestamp will be millisecond accurate. As for sending data out via USB – how does the USB system schedule transmitting data? Is there a way to request data to be sent immediately, or is data shoved into a buffer to be sent “whenever”? I would imagine the former case, as otherwise mass storage device writes would be unbelievably tedious…? |
Dave Higton (1515) 3534 posts |
Then it’s not a hard real time system. There’s no way to get millisecond resolution events with the system you describe; it would be no better than we have now. I don’t know the correct names (Colin, please help us out) for the parts of the USB system, but, for USB transmission, there is a buffer (or set of buffers) whose data are read and transmitted by the USB interface chip. I presume this must be DMA? My aim is to get data into these buffers as an immediate result of a 1kHz clock tick, without waiting for RISC OS to “get round to it”. I can already see a problem, if the buffers have already been filled with data to be sent, and we come along with some to be sent NOW. |
Rick Murray (539) 13850 posts |
RISC OS is not a hard realtime system. Let’s say you’re reading MIDI events from USB to write to a file on disc. Why do you think my MIDI module responds to a periodic ticker and then schedules a callback? It’s because reading the data (from an opened file handle) goes horribly wrong. Reading directly from the buffer (bypassing the file handling) would probably work, I’ve yet to look into doing that. However, point still stands – you’re somewhat limited in what you can actually do when you hang off an interrupt and other stuff is “threaded” and the OS is busy.
Huh? Didn’t you just propose CallAtTick to run at 1kHz? There’s your millisecond resolution event right there. It’ll behave like the centisecond resolution event, only faster. No. You can’t pass through to a foreground application at millisecond resolution. If that’s what you want, you’ll need another OS. RISC OS can’t do it. Look at all the issues of reentrancy, and why there’s a <beep>ton of stuff you can’t do in events, service call handlers, etc etc.
One could tag incoming MIDI events with a millisecond resolution timestamp. That’s quite a lot better than we have now.
Question, I guess, is:
Uhh… Something comes to mind. Accessing USB devices using the filesystem method implicates DeviceFS and BufferManager, etc etc. It’s a little complicated (why I still use the file BGet/BPut method). But mass storage devices don’t appear to work like this. So either the low level USB system directly handles USB storage in a special way itself, or there’s a way of talking to devices bypassing the file/buffer stuff. If it is possible to indeed talk to the USB system directly (and not via pasting data into buffers), then one would imagine that it sends data as it is given it? I’m absolutely not qualified to answer this as I’m not familiar with USB, but it’s worth looking at as file handles can be unwound to buffer references (bypassing file handling), so can it be further unwound to talking directly to the driver (bypassing buffers)? |
Dave Higton (1515) 3534 posts |
Sorry, I’m being a bit loose with my words there. I am very well aware that RISC OS is not a real time OS, but, as I believe I said somewhere above, it may be possible to add a real time subsystem into RISC OS. That’s what I’m interested in exploring now. |
Dave Higton (1515) 3534 posts |
Yes – and no… It’s better than what we have on RISC OS 5. However, if you look at the old serial MIDI implementation from the Archimedes and A3000-series machines, I believe that’s what we got. Better than what we have now, but exactly as good as we had 30 years ago. I was looking for my manual for my old A3000 MIDI podule last night, but I can’t find it. Maybe I threw it out, believing it would never be relevant again. I did write a MIDI recorder and replayer for it, many years ago. They worked nicely. Long lost, though. I still have the Yamaha ME50 that I used it with. |
Colin (478) 2433 posts |
When you open an OUT endpoint and write to it the data is sent immediately if the buffer is empty. The data is removed from the buffer on successful transfer and if there is more data in the buffer that has arrived later that is transferred at this point. For IN endpoints the Upcall_RxDataPresent upcall happens when data enters an empty buffer and this happens directly from the USB interrupt – ie no callback is involved. This is the scheme used by EtherUSB and my SerialUSB module. Presumably you could timestamp incoming data in the Upcall_RxDataPresent upcall then move the data to another (larger) buffer for use by the forground. My SerialUSB module does something like this for serial usb devices. It keeps emptying the USB devicefs buffer at Upcall_RxDataPresent and puts the data into another devicefs buffer for use by applications. This allows the SerialUSB device to have Serial special fields so that it works like a standard serial device but you could have Midi config options. |