Jump to content
IGNORED

Play a note via MIDIMATE


fox

Recommended Posts

How do I play a note via MIDIMATE? I'm trying the following code but hear nothing in Altirra:

	org	$6000
main
	sei
	ldy	#7
	lda	#0
	sta:rpl	^20,y-
	mva	#$28	^28
	mva	#$15	^24
	mva	#$23	^2f

	mva	#0	^2e
	mva	#$10	^2e
	mvx	#$c0	^2d
	ldx	#$01	; instrument
	jsr	send

	ldx	#$90
	jsr	send
	ldx	#$3c	; middle C
	jsr	send
	ldx	#$7f
	jsr	send

	mva	$10	^2e
	cli
	rts

send
	lda	#$10
	and:rne	^2e
	sta	^2e
	mva	#$10	^2e
	stx	^2d
	rts

	run	main
	end

Link to comment
Share on other sites

There are some setup problems in the serial communication:

 

The serial rate is out of spec. MIDI requires 31.250Kbaud +/- 1%, while a POKEY divisor of $15 corresponds to 31.960Kbaud for NTSC or 31.667Kbaud for PAL. POKEY can't hit this baud rate with sufficient accuracy, so MIDIMATE supplies an external 4MHz/128 clock to use. You need to assert the motor line (PACTL=$34) and enable sending with the external clock (SKCTL=$13).

 

There is, however, a bug in Altirra's MIDI parsing of SysEx messages that is triggering here -- it is trying to parse the program change message as a 3-byte message instead of a 2-byte message. You can work around this by sending a padding $00 byte. I'll fix this for the next release.

 

I'd also recommend waiting for the serial transmission to fully complete before exiting, just in case something is going to reset the serial port immediately after. Waiting for serial output ready and then serial output complete is required to ensure that the last byte is completely sent.

  • Like 5
Link to comment
Share on other sites

Thank you! It works.

 

I noticed that MIDI Sequencer by Maciej Sygit uses the $15 divisor. The difference seem small enough to transmit one byte if the MIDI device synchronizes on every start bit - does it? Is the 4MHz/128 clock internal to MIDIMATE? I don't know what's inside MIDIMATE, but I know that in the '90s people used a simple "wires-only" SIO-MIDI interface.

 

The minimum set of changes was: motor on, a padding byte and waiting for transmission to complete:

	org	$6000
main
	sei
	mva	#$34	^32	; motor on
	ldy	#7
	lda	#0
	sta:rpl	^20,y-
	mva	#$28	^28
	mva	#$15	^24
	mva	#$23	^2f

	mva	#0	^2e
	mva	#$10	^2e
	mvx	#$c0	^2d
	ldx	#$01	; instrument
	jsr	send
	ldx	#$00	; padding needed for Altirra
	jsr	send

	ldx	#$90
	jsr	send
	ldx	#$3c	; middle C
	jsr	send
	ldx	#$7f
	jsr	send

	lda	#8
	and:rne	^2e	; wait for transmission complete

	mva	#3	^2f
	mva	$10	^2e
	cli
	rts

send
	lda	#$10
	and:rne	^2e
	sta	^2e
	mva	#$10	^2e
	stx	^2d
	rts

	run	main
	end

Link to comment
Share on other sites

I just released 2.99-test24, which should no longer need the $00 padding workaround.

 

The 4MHz/128 clock is indeed built into the MidiMate. Activating the motor control line enables two features on the MidiMate, one being the 31.25KHz clock for POKEY to use, and another connecting the SYNC input to the SIO INTERRUPT line for synchronization purposes. Software written for the actual MidiMate will not work with an adapter that doesn't provide this external clock, as it'll set POKEY to use the nonexistent serial clock and serial output will never complete.

 

As for whether you can get away with using an out-of-spec clock, it depends. I have no experience with actual MIDI hardware, so I couldn't say. If you were just using MidiMate-like adapters to network Ataris, then POKEY would be handling the receiving end and you could probably get away with it. There's no guarantee that other MIDI devices synchronize to the incoming stream the way POKEY does, however. On top of that you have analog signal effects to deal with. Thinking of the input as a perfectly clean square wave can lead you to believe you can get away with +/-5% in baud rate, but real-world effects mean you'll want to be much better than that.

	lda	#8
	and:rne	^2e	; wait for transmission complete

This isn't quite safe -- you need to wait for output ready first ($10) and only then wait for output complete ($08). This is because of a quirk/bug in POKEY where the output complete IRQ can stay on for up to half a bit until the last byte begins shifting out, and the serial output complete IRQ is actually the "not shifting" signal internally. The serial output ready IRQ trips when a byte is transferred from SEROUT to the shift register, so after it fires you can be sure that the output complete IRQ has turned off.

  • Like 4
Link to comment
Share on other sites

The MIDI protocol allows for certain types of messages to be sent without a status byte. The receiving device will then use the last status byte it received. This is called running status and its purpose is to minimize bandwidth used.

 

For example if the bytes 0x90 0x41 0x7f 0x43 0x7f are sent to the serial output, midiOutShortMsg should be called twice

midiOutShortMsg(out, 0x7f4190);

midiOutShortMsg(out, 0x7f43);

Altirra does only the first call.

 

More complicated example, those bytes: 0x90 0xfa 0x41 0x00 0x43 0xfc 0x00 are really four messages

midiOutShortMsg(out, 0xfa);

midiOutShortMsg(out, 0x4190);

midiOutShortMsg(out, 0xfc);

midiOutShortMsg(out, 0x43);

 

Messages 0xfa and 0xfc are MIDI real-time messages they can be interspersed with any other message and they don't cancel running status.

  • Like 1
Link to comment
Share on other sites

I confirm that Altirra 2.99-test24 doesn't require the padding byte.
What's the use of SYNC input? SIO INTERRUPT is a PIA IRQ?
I think that MIDI devices have to sync on the start bit, otherwise they could be probing at the signal edges. And the clocks aren't probably perfect.
Thanks for pointing out the problems with analog distortions and awaiting completion.

More complicated example, those bytes: 0x90 0xfa 0x41 0x00 0x43 0xfc 0x00 are really four messages

midiOutShortMsg(out, 0xfa);

midiOutShortMsg(out, 0x4190);

midiOutShortMsg(out, 0xfc);

midiOutShortMsg(out, 0x43);

 

Messages 0xfa and 0xfc are MIDI real-time messages they can be interspersed with any other message and they don't cancel running status.

Doesn't 0x43 have the implicit command 0x90? If so, why is it reordered with 0xfc?

Link to comment
Share on other sites

0x90 is a note-on message which requires two data bytes. 0x43 is just the first data byte, so we have to wait for the second one, 0x00 in this case. On the other hand 0xfc can be sent immediately after it was received. The last call to MidiOutShortMsg sends two bytes, I could have written it: midiOutShortMsg(out, 0x0043); but writing leading zeroes seemed unnecessary to me.

Link to comment
Share on other sites

The MidiMate has SYNC IN and SYNC OUT connectors to allow an audio tape to be used for a clock track. The SIO INTERRUPT line is connected to PIA CB1 and thus SYNC IN allows the tape signal to trigger CB1 interrupts. On the output side, the SIO CLOCK OUT signal from the computer is used to record a clock track on tape.

Link to comment
Share on other sites

So it's for a regular tape recorder?

Yup, just provides a very simple trigger signal at regular intervals. MidiTrack III supports it, but I haven't actually tested this feature on the real MidiMate -- I'd have to dig around for an adapter since the SYNC inputs are big 3/8" plugs.

 

Regarding the motor control signal: should there be a delay between activating it and starting to send? If so, how long? Should I turn it off after I send all the notes?

 

Shouldn't need a delay to start, but you do need to wait for the transmission to fully end before stopping it. The motor control is only used to gate the external clock and doesn't send any other signal on the MIDI bus, so it only needs to be on as long as POKEY needs a serial clock. Treat it the same way you'd treat the applicable bits in AUDCTL ($D208) and SKCTL ($D20F) during a regular SIO bus transfer.

Link to comment
Share on other sites

Sorry, let me clarify. What I meant was that it's not like the SIO COMMAND line, which is a separate signal that the device can see directly. The SIO spec requires a small delay there because the device needs time to turn around from checking COMMAND to receiving serial data. When using SIO MOTOR for a tape drive, you also need a delay because the tape motor needs time to spin up. Neither of these are needed with the MidiMate because the motor control signal doesn't go out on the MIDI bus and devices can't see it, so you can toggle it immediately before and after sending a byte. But you do need it asserted to do any MIDI communication with the MidiMate, because it enables everything -- SIO data in, data out, clock in, clock out, and interrupt are all gated by motor control. If it's off, then there's no connection to the MIDI bus at all and no interference with other SIO bus devices.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...