Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mockingboard: music not working when using Timer1 from both 6522's #685

Closed
tomcw opened this issue Sep 2, 2019 · 13 comments

Comments

@tomcw
Copy link
Contributor

commented Sep 2, 2019

Repro setup:
Offset-0x00 6522: Timer1 (continuous mode) for music playback, eg. at 50Hz
Offset-0x80 6522: Timer1 (continuous mode) for other purpose

Not configuring the offset-0x80 Timer1 for continuous mode allows music playback to work.

@Archange427

This comment has been minimized.

Copy link

commented Sep 4, 2019

To be precise (I had personally asked Tom to remain vague while waiting for the official release - Thanls Tom), this issue concerns CHIP, the last Musidisk from French Touch.

Here is part of the email that I sent him with more details:

This release uses 2 interrupts (Timer 1 from both 6522).
The first one is synchronized with display (50Hz). The purpose is to display a visual representation of the CPU time used by the player to play one tick.
I swap to page 2 before to play one tick and a swap again to page 1.
But, I added to that, to make it a little more shimmering ;) , a hires display in the first part of the screen.
Hence the use of the second interrupt!
As playing one tick does not always use the same machine time, the second interrupt is here to swap to TEXT mode at the same line, whatever time used by playing routine...

And here comes the issue with AppleWin: I had no sound at all... The play routine is well executed, the AY registers are set but nothing happens!

I need only disable the second interrupt to restore sound (the sound being played during the first INT)...

To set interrupts, I use:

        LDA #%01000000      ; Continuous Interrupt T1 / PB7 disabled (b76)
        STA $C40B                  ; Auxiliary Control Register
  (1)   STA $C48B                  ; same for second 6522

        LDA #%11000000     ;
        STA $C40D                 ; Interrupt Flag Register   (Time Out of Timer 1 Int)
        STA $C40E                 ; Interrupt Enable Register (Enable Timer 1)
   (2)  STA $C48D                ; same for second 6522
   (2)  STA $C48E          

If I disable INT by commenting on both lines (2), sound is not restored...
But if I disable INT by commenting on line (1), sound is restored...

I obviously tested on a real Apple II (now I can!) and sound is played correctly, using both interrupts. And display is the one expected.
Important to note, however, I have a Mega Audio and not a "real" Mockingboard.
I do not know if it matters... but Mega Audio (from A2heaven) emulates Mockingboard... No real AY-3-8910 or 6522 on board...

Edit: Full source code available here: http://fr3nch.t0uch.free.fr/CHP/CHP.html

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 4, 2019

Great, thanks Arnaud for sharing all these details.
Internally I have a working solution, but I want to consider it a little longer.

btw. Very nice demo & tunes. I haven't heard LED Storm in years! :-) Smart use of 2 interrupts too.

@Archange427

This comment has been minimized.

Copy link

commented Sep 5, 2019

Great news!
Can you explain where the issue comes from?
Because it seems really strange. Both interrupts seem to work properly, the display is perfect...
Just... no sound!
Very weird.

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 5, 2019

The problem starts with: when to update the Mockingboard sound ring-buffer?

The emulator has a ~0.4 second ring-buffer for Mockingboard sound. Periodically the emulator will update this sound buffer. The period I chose for AppleWin to update at is the TIMER1 interval (eg. typically 60Hz). It's best to do this after the AY8910 registers have been updated (ie. not mid-way through updating them), so AppleWin was doing it when the TIMER1 interrupt occurred.

AppleWin saved the number of the 6522 of the last TIMER1 (eg. AppleWin has 4x TIMER1's: 2 6522's per Mockingboard x 2 supported Mockingboards). Then when a TIMER1 underflow interrupt occurred, it checked that the 6522 number matched the last TIMER1 to be setup.

So here's what was happening:

  • 6522[0].TIMER1 = 50Hz
    • set lastTIMER1 = 0
  • 6522[1].TIMER1 = 50Hz
    • set lastTIMER1 = 1
  • 6522[0].TIMER1 underflows and sets IRQ
    • Since lastTIMER1 != 0, so don't update Mockingboard sound
    • Restart timer1: set lastTIMER1 = 0
  • 6522[1].TIMER1 underflows and sets IRQ
    • Since lastTIMER1 != 1, so don't update Mockingboard sound
    • Restart timer1: set lastTIMER1 = 1
  • 6522[0].TIMER1 underflows and sets IRQ
    • Since lastTIMER1 != 0, so don't update Mockingboard sound
    • Restart timer1: set lastTIMER1 = 0
  • ...

Basically the 6522 TIMER1 underflowing never matched the expected lastTIMER1... so silence!

The fix involves counting cycles between Mockingboard updates to determine the update interval. Currently I special-case this for when there are multiple TIMER1's active. I think I can evolve this into a generic solution, but need more time to test this idea. So for now, I'll just go with the special-case.

@Archange427

This comment has been minimized.

Copy link

commented Sep 5, 2019

Wow, very interesting.
But reading the explanation, something immediately comes to my mind:
What happens if no interrupts are used at all ? (like in FAKE OFF for example ...)
When do you update the Mockingboard sound ring-buffer?

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 6, 2019

What happens if no interrupts are used at all ?

OK, so I didn't give the whole story... 2 other cases:

  1. Playback of continuous tone (eg. just POKE the 6522/AY8910 registers)
    • without any TIMER1 interval then AppleWin just updates the sound buffer at the end of every Apple II video frame, ie. every 60 or 50Hz.
  2. TIMER1 is polled (and 6522.IER.TIMER1 interrupt is not enabled)
    • 6502 polls 6522.IFR to determine when TIMER1 underflows
    • this is just like the regular TIMER1/interrupt case: the sound-buffer is updated on TIMER1 underflow, ie. the interval of TIMER1.

Which method does FAKE OFF use?

@Archange427

This comment has been minimized.

Copy link

commented Sep 6, 2019

Just a very simple loop that launches the "play" routine as quickly as possible (as it is to generate "samples").
So I guess we are in the case 1.
But precisely for this very specific case (samples), is the Mockingboard sound buffer update enough compared to a real machine?!
(even if in fact there is only one volume register that is changed)

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 6, 2019

But precisely for this very specific case (samples), is the Mockingboard sound buffer update enough compared to a real machine?!

Yes. The back-end emulation for AY8910 is from a Spectrum 128 emulator ("fuse"). For the current (eg) 60Hz frame, every AY8910 access is recorded with a timestamp. Then when AppleWin updates the sound-buffer, these AY8910 accesses are converted into signed 16-bit audio samples, which are then written to the sound-buffer.

So even though AppleWin only updates the sound-buffer (eg) at 60Hz, all the AY8910 accesses are correctly "played back" at the correct time. This is why AppleWin is able to play samples using the AY8910.

@Archange427

This comment has been minimized.

Copy link

commented Sep 6, 2019

Stupid question, brilliant answer!

tomcw added a commit that referenced this issue Sep 6, 2019
@tomcw tomcw added this to the 1.29.2 milestone Sep 6, 2019
@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 6, 2019

On the contrary: you are asking some good questions... and I need to reassess the Mockingboard sound-buffer update logic. But for now it's good enough :-)

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 6, 2019

FYI, new AppleWin build 1.29.2 here.

@Archange427

This comment has been minimized.

Copy link

commented Sep 7, 2019

Thanks Tom. Very good job! And very fast reaction.
I hope to offer a bigger challenge next time ;)

@tomcw

This comment has been minimized.

Copy link
Contributor Author

commented Sep 7, 2019

Thanks for checking it. I'll close this now.

@tomcw tomcw closed this Sep 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.