It is the 1739th of March 2020 (aka the 3rd of December 2024)
You are 18.97.14.81,
pleased to meet you!
mailto:blog-at-heyrick-dot-eu
MIDI and the broken brain
No, I didn't expect to issue two SimpleSeq updates in one weekend. If I'd have known I'd have just done one today and not yesterday.
But I had the clever idea of finally hooking that old Roland E-16 up with the USB-to-serial-MIDI adaptor.
You know, the piece of crap that will make you tear your hair out?
Two plugs, the way MIDI used to be.
Well, I'm now bald as I'm the programmer who got one single note playing from an entire piece.
And from there, a whole wild goose chase.
Now, I know why I was only hearing one note. Those little adaptors will wet themselves if you toss more than four or five notes at the same time, leading to the thing either failing to do anything useful or spewing garbage.
Which meant that I needed to apply the artificial delay. Easy.
SYS "MIDI_Options", -1, 1
Aaaaannddd... down the rabbit hole I went. Because that didn't work. I looked at the MIDI module and discovered the cause. In the various changes and manipulations, the necessary code had been removed.
THAT LINE OF CODE WAS IMPORTANT! Rubbishy adaptors need to have a delay in order that they can sort-of work. Okay, granted, is is freezing the entire system for 320×4µs for each note, but that's the price you gotta pay for cheaping out on the MIDI adaptor.
That didn't work either.
Huh?
I played around with the SimpleSeq source, dropping a GFX_Wait() call after every note was played. It was dead slow and took forever, but it did play them.
So my next test was to see if there was a more workable delay. I found that this, after each note, worked fairly well.
for ( int oh_ffs = 0; oh_ffs < 200; oh_ffs++ )
_kernel_swi(SWI_OS_GenerateError + XOS_Bit, &r, &r);
Yes, that is essentially calling the SWI to raise an error with the X bit meaning "don't raise an error", and doing it two hundred times.
If you felt a little bit of your soul wither and die just looking at that, imagine how I felt having written it.
But it worked. Things played. And in more or less the right time as well.
Which meant, back to the MIDI module. I tried various options, even at one stage calling the delay routine with a value of 1,000,000 which given as it takes a time in microseconds, should have delayed for a whole second after every note.
It didn't.
It didn't delay at all.
So I went and did some gardening. Taunted kitty when it rained on us and she was not happy.
Came back in, looked at the function to perform the delay.
microtick_delay
; Entry:
; R0 = Number of *microseconds* to delay for
; Exit:
; -
STMFD R13!, {R1-R9, R14}
MOV R8, #0 ; Should be zero
MOV R9, #11 ; HAL_CounterDelay
SWI &2007A ; XOS_Hardware
LDMFD R13!, {R1-R9, PC}
Okay, it's setting R8 to zero, R9 is the function pointer, and it'll be picking up R0 on entry as the number of microseconds. Everything looks like it belongs. But, better paranoid than not. So is &2007A the right SWI? Yup, &7A is OS_Hardware, and the &20000 sets the X bit so it won't raise an error.
Is 11 the right call?
Um, hang on... I'm querying the FIQ status of device #1,280? No, that ain't right. HAL_CounterDelay is twice that, it's 22.
The code amended, the module rebuilt, and suddenly... success!
Of course, had I had by brain in gear and a lot more tea in me than my habitual barrelful, I might have hit upon this solution at 2pm instead of 5pm by concentrating on the painfully obvious clues rather than getting sidetracked by nonsense.
But it's not over yet. The Roland-E16 played some music but not all of it, and it didn't play any drum sounds, like at all.
The reason for the drum sounds is because I had set the default drum kit to #1, because that's what it says in the booklets, despite the very painfully obvious fact that it's always off-by-one because the byte actually sent is in the range 0-127 and the instruments are in the range 1-128. Which is doubly stupid when most guides will show the bank select alongside which is in the range 0-127. That's consistency for you.
So it's not really any wonder I got a little bit confused, is it?
My Yamaha keyboard has a drum kit #2 which is pretty much the same as the default, with some really subtle changes.
The Roland does not, it numbers the drum kits in an eccentric way (1, 9, 17, 25, 26, 33, 41, 49, and 57 - subtract 1 from each for the actual value to give via MIDI) and being told to use the second kit when there was no such thing, it simply ceased to make any noises at all on the drum channel.
So for now I force drum kit #0 when setting up to play.
The second problem can be seen if we look at the top of the MIDI implementation chart for the keyboard.
Not a complete MIDI implementation.
As you can see, the keyboard responds to MIDI channels 1, 3, 4, 5, 8, 10, and 16.
Only, it doesn't.
It responds to channels 1-5, and 10. Channel 8 doesn't seem to be recognised even when setting a bass voice. And channel 16 is marked "Note to arranger" so it is possible that it only handles control messages and isn't an instrument.
It gets even weirder. The usual channel that the keyboard outputs on is channel 4, the "upper" (even when you switch the setting to lower!). However if you press multiple keys at the same time, the first will be on channel 4 and the rest will be on the accompaniment channel 1.
P.Ch # Data Time Annotation
---- - ------------- -------- --------------------
0.04 3 &93, 48, 65 215078 Note on (channel 4)
0.04 3 &93, 52, 64 215643 Note on (channel 4)
0.04 3 &93, 55, 88 216162 Note on (channel 4)
0.04 3 &93, 59, 75 216695 Note on (channel 4)
0.04 3 &93, 52, 0 218178 Note off (channel 4)
0.01 3 &90, 55, 0 218181 Note off (channel 1)
0.01 3 &90, 59, 0 218184 Note off (channel 1)
0.01 3 &90, 48, 0 218200 Note off (channel 1)
The notes were played one by one so they appear on channel 4. Then they were released at the same time (the time given is in milliseconds and may be how long it took for the MIDI translation) which meant that the first note off is on channel 4 while the rest is on channel 1.
Which means that this gonzo keyboard is turning notes on and off across channels.
Now most of my music plays, provided it doesn't use unsupported channels which won't play.
You know, you wouldn't have thought one would be saying such a thing about an instrument, would you? It's like "here's a guitar but you can only pluck/strum two strings at once".
It's a shame, because the E-16 does make some pleasing noises. There are also some interesting features like splitting the keyboard in two so the lower two octaves can be one instrument and the upper three can be another. Of course, my Yamaha can as well, but this Roland is like two decades older.
I am, actually, trying to figure out what sort of demographic the Roland is aimed at. It's not a "portable" keyboard as it doesn't run on batteries. It needs a power brick. But, on the other hand, it has little rubber feet underneath and no mounting slots or screw holes for fitting it to a keyboard stand. So... <shrug>?
So, I'm back to the Yamaha for development and work... but I now know that SimpleSeq works with older keyboards using crappy interfaces...and that the MIDI module supports them correctly once again.
Next week...just gonna watch movies on Netflix like I had planned...
SimpleSeq v0.22
Much has been described above.
The only real difference is that going into the music setup, there's a new option for hardware fudge to let you wait a smidgen between notes.
Music setup.
At this time, it's an option stored in the music file itself, as SimpleSeq doesn't have a global configuration. This means you'll need to set it for each music file.
Here is the updated MIDI module that, now, correctly works with crappy hardware.
You don't need this if you downloaded SimpleSeq as that comes with MIDI 0.12; but you might want it to place into System and/or the sources. There are outstanding issues, this is pretty much just a modification to cater to this specific problem.
Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺ ADDING COMMENTS DOES NOT WORK IF READING TRANSLATED VERSIONS.
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.
John, 11th February 2024, 23:17
I've been meaning to ask for ages; why is your site icon a picture of a 13A UK ring-main plug?
You know, the one that appears in the URL bar between the URL and the padlock.
And is this not used at all in the mobile version?
Rick, 12th February 2024, 00:05
You mean the spinning thing? https://heyrick.eu/blog/favicon.ico
It's an anime bunny!
John, 12th February 2024, 23:45
Ah - it doesn't spin in NetSurf!
jgh, 13th February 2024, 00:35
I had to do a similar spin-do-nothing loop with the RT11 keyboard host for my PDP11 BASIC. If you just polled the STDIN, you couldn't tell the difference between the <ESC> key being pressed, and the start of an <esc> sequence.... *sometimes*.
An <esc> sequence is supposed to return the full stream continously to every STDIN call. Except when it doesn't because it's actually coming over a virtual link and, guess what, packetisation! Which gets worse if using a USB-Serial adapter. "Hey, I think I'll gather these keypresses and only send them when my local buffer is full".
I inserted a call to GetTime planning on counting a number of ticks. It turned out that the time to make the EMT call, switch modes, index into the dispatch table, call the routine, check the hardware, unwind everything and return to the caller was just enough. So I just stuck two EMT GetTime calls in with R0=0 saying "give me zero bytes of data"... ;)
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.