MSU1 A/V synchronization

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: MSU1 A/V synchronization

Post by Near »

ikari_01 wrote:Regarding resume someone has come up with something: https://github.com/mlarouche/sd2snes/co ... b0cb74d1d2
I believe he said he based that around the discussion on my forum around this. Which was before you and I talked via e-mail.

Certainly this would be much more in the spirit of MSU1's simplicity.

But the resume bit sounds like the older functionality that had some flaws around seek delays. If $2007.d2=1 forced a seek to a new resume location, then it would have to set the audio busy flags and wait for the media to seek+buffer samples at the new location. It forces two seeks, one for track select, one for resume.

So here's my current thinking on this. Note that it's not finalized yet, I'm open to discussion still.

Start with two 32-bit values, flushed at reset or power cycle (if possible, otherwise just on power):
uint32_t track = 0; //no track (note: since offset=0 below, this is equivalent to there being no track/seek)
uint32_t offset = 0; //no offset (note: value is in SAMPLES (32-bit), not bytes (8-bit))

Step 1: stop existing track

$2007.d2 is now the "save" bit. On writes to $2007:

A: if $2000.d6=1 (audio busy), stop right here, do nothing.

B: else, if $2007.d0=1, then unpause the track if need be, but do nothing with the track/offset variables and ignore the "save" bit entirely. The track is playing, so trying to cache the offset is pointless. You'd end up resuming too soon.

C: else ($2007.d0=0), if $2007.d2=1, then save current track# and current offset into track/offset variables. You can do this over and over if you like.

D: else ($2007.d2=0 && $2007.d0=0), this has no effect on the track/offset variables.

Step 2: play new track

Now go ahead and play your new track.

Upon writing to audio track high ($2005), it will compare the currently selected track# against the saved track#. If there's a match, then the offset will be taken from our saved variable. This allows the audio seek delay to happen all at once (for both track + track position). Otherwise (if the current track# != the saved variable track#), it will seek to the beginning of the track.

Step 3: stop the new track

When we stop our new track, we don't want to erase the old track/offset, so make sure $2007.d2=0 here.

Step 4: resume the old track

We select the old track, and on the $2005 write, the track#s match up, so we seek to the saved resume offset. Furthermore, we flush the track+resume variables back to 0, since there's no use for them anymore. We've already resumed. This is also needed for our edge case no-resume described below to work.

Upon playing the track with $2007.d0=1 (unpause), it will have resumed playback where it last left off.

Edge case: do -not- resume old track

You saved the position of a song, but now you want to discard it and start from the beginning instead.

IDEALLY, I'd love to make $2005.d7 = resume bit. But this would break backward-compatibility. Older MSU1 implementations would try and load audio track 32768+.

So we have be more pragmatic here. Instead, select your old track, and it'll automatically resume on $2005 write.
Now immediately write $2004-5 to select the same track# a second time.
Since the resume information was flushed away, it will definitely play from the beginning this time.
Unfortunately, doing this will require two seek operations.

The good news is, this edge case should be very rare. Let's take Chrono Trigger as the example game:
* if you are playing overworld theme -and- you're changing to battle music, you know you need to save the offset
* if you are playing overworld theme -and- you're changing to town music, you know you shouldn't save the offset
* if you are playing battle or town music and change to anything else, you know you never need to save those at all
There shouldn't be any cases where this edge case behavior is needed in most games.

Notes

The main takeaway here is that we're only capable of suspending and resuming one single track.

The thing is, you can have up to 65536 tracks on the MSU1. And if we saved a 32-bit sample# for each and every track (we could kill off the track# in that case), that would be 256KiB of memory required in the pathological worst case. That's too much memory for the sd2snes.

In the future, if there's some compelling reason to have 2+ track resume, we can consider changing the track/offset variables to:
uint32_t track[N];
uint32_t offset[N];
And use them to store in free slots where available. But I don't foresee us ever needing to do that. It would be jarring and weird to resume multiple tracks like that.

The advantages over DarkShock's example (my older tecnique):
* this will allow you to cache a new resume without having to flush an old one first (important as you may not know one was already cached)
* this will avoid the need for a seek operation on $2007 write (which was not part of MSU1 originally)

This new proposed behavior would be fully backward-compatible with the old MSU1.
The only effect would be that your resumed music would start over instead of resuming.
There's never really a case where this is going to *ruin* the game, it'll just be a bit less enjoyable.

Anyway, again, open to suggestions.
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

I'd like to go back to SNES timing for a second because I just got this in. RetroDan posts in this thread his measurements of SNES vertical refresh rates:
RetroDan wrote:Okay. Looks like the most consistent average is 60.24Hz at about two-thirds of the time, with 59.52Hz occupying the other third. Doing a weighted average calculation gives us a rough average refresh rate of 60.0024Hz. Nice and tidy.
59.52Hz might point to a 21.28MHz master clock but even 60.24Hz is less than the 60.99Hz we have been assuming so far. Any ideas? Are we wrong about frame cycle count? Are his measurements bad?

EDIT: Quoting myself on my original MSU1 timing considerations:
ikari_01 wrote:On a perfectly tuned NTSC SNES the actual playback rate equals 44308.06Hz
44308.06 / 44100 * 59.97 = 60.25Hz
So RetroDan's 60.24Hz actually come quite close to my own measurement back then. I got perfect A/V sync with these settings, and measuring frame cycle count with a logic analyzer (locked to the SNES master clock) I even got a different cycle count that what is considered canon.
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

I'm ok with this resume scheme (actually I don't mind either yours or DarkShock's). Strictly speaking we already have a situation where there's a seek that is supposed to be zero-delay (loop points) so the one seek on resume wouldn't hurt too much in my opinion. I am slightly in favor of your proposal though. ;)

If multiple resume points are an issue there's an alternative: make the interface more generic overall. Expose playback position and leave it up to software to manage it. This would require a register expansion though.

$2008-$200b: playback position / seek request in samples (r/w)

This would be an S-SMP style dual register.
Reading $2008 copies the internal playback position into the "read" register so it doesn't change during readout. Can be read at any time.
Writes to $2008-$200b go into the "write" register.
Writing $200b also sets a seek request (or "resume") flag for the next track request. It gets cleared after writing $2005.

An added benefit of this is that software is given an actual means of synchronizing with audio playback by tracking the sample count.
The challenge for me would be to maintain the correct playback position in the FPGA wrt loop points. Not a big deal.

As far as I can tell this is backward compatible too.
New software that relies on playback position for synchronization should check MSU1 revision number. Software that just wants to use the resume buffer can just do so. Old MSU1 will return open-bus but writes will have no effect either so it will just act as though there were no resume feature.
The extension should be entirely transparent to old software as $2000-$2007 remain unchanged entirely (save for the revision number).
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: MSU1 A/V synchronization

Post by lidnariq »

ikari_01 wrote:59.52Hz might point to a 21.28MHz master clock but even 60.24Hz is less than the 60.99Hz we have been assuming so far. Any ideas? Are we wrong about frame cycle count? Are his measurements bad?
Shouldn't it be 60.09 Hz, not 60.99 Hz?

Really not clear about where 60.24 is coming from; the NTSC rate should be approximately 21.477MHz ÷ 1364 ÷ 262 ... and even if you replaced 262 by 261 that's not 60.24 either.
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

Yes, 60.09Hz, sorry.
I'm not so sure about the actual cycles per frame on the SNES anymore... going to wire the LA once again.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: MSU1 A/V synchronization

Post by Near »

An NTSC video frame is 262 scanlines * 1364 clocks. With the odd caveat that odd frames are missing 4 clocks on scanline 240 in non-interlace mode. So subtract 2 clocks to average that out.

262*1364-2=357366 clocks per frame.

The crystal clock on the SNES is rated for 315/88*6 MHz.

Thus: 315/88*6,000,000/357,366=60.098813897440515529533511098629hz

I posted a response on the board ikari linked to as well. Basically, these crystals are 25 years old now. They drift more and more as they age. The SNES PCB even has a trimpot on it to adjust the timing of this crystal as such.

It doesn't matter how many real SNES consoles you analyze and then do an average on: the hardware is too old to get reliable "actual" clock rates anymore. So in this case, I'm going by the specification of an ideally functioning SNES.

On that subject however, the SMP uses a ceramic oscillator, which has an even greater tolerance right out of the box (0.5% vs 0.001% for quartz). On this side, we have whoever the alpha-ii.com guy is saying he's clocked this around 32040*768hz more than a dozen years ago: http://alpha-ii.com/Info/snes-spdif.html
I do actually honor this rating because that seems to have been consistent across all the consoles back then for the SPDIF mod. I've also asked others to verify that many years ago, and they all confirmed similar results.

Also, higan emulates the MSU1 as if it has its own 44100hz oscillator, so it's immune to the effects of the SNES CPU's clock. If you base your own clock on the sd2snes off of the SNES CPU clock, then I'm not really sure how to compensate for that. My suggestion would be to adjust the trimpot while it's hooked up to an oscilliscope until you get as close as possible to 315/88*6MHz. And base sd2snes off of this ideal state. If the +/-0.001% variance still holds after this adjustment, then you should most likely be good for an hour-long session in BS Zelda without the difference becoming very noticeable.

Really, the problem lies in BS Zelda basing its timing off of NMIs, which are based on the SNES CPU clock speed. Whereas MSU1's audio timing is based on Redbook audio, which is always exactly 44100hz. Frankly, I don't understand how a satellite radio broadcast could have possibly compensated for different SNES units running at slightly different clock speeds by timing things through NMI, but ... I don't know. Most of the Satellaview service is a mystery to me, given that I've never seen the service live.
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

byuu wrote:the hardware is too old to get reliable "actual" clock rates anymore So in this case, I'm going by the specification of an ideally functioning SNES.
But surely you can still count the master cycles per frame which are independent of the actual clock frequency. I think I got something other than 357366 back then and I'm going to verify it again.
byuu wrote:Really, the problem lies in BS Zelda basing its timing off of NMIs, which are based on the SNES CPU clock speed. Whereas MSU1's audio timing is based on Redbook audio, which is always exactly 44100hz. Frankly, I don't understand how a satellite radio broadcast could have possibly compensated for different SNES units running at slightly different clock speeds by timing things through NMI, but ... I don't know. Most of the Satellaview service is a mystery to me, given that I've never seen the service live.
I think only the hack bases its timing off NMIs. The original game got the clock via satellite, same source the sound came from.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: MSU1 A/V synchronization

Post by Near »

> But surely you can still count the master cycles per frame which are independent of the actual clock frequency.

Yes, definitely.

> I think I got something other than 357366 back then and I'm going to verify it again.

There are few things I can say with absolute certainty, but I am 100% positive that non-interlaced NTSC alternates between 357368 and 357364 clock ticks per frame. If you try and count with software, keep in mind that 40 clocks per scanline are lost to DRAM refresh.

> I think only the hack bases its timing off NMIs. The original game got the clock via satellite, same source the sound came from.

Ah, I see. So the satellite link had its own RTC. That does make a lot more sense :D
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

357366 confirmed (on a 2-1-3 SFC). ;) I can't recall what my previous result was or what went wrong back then... :roll:
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

So, with that sorted out, any opinion on this? viewtopic.php?p=156081#p156081
Conn
Posts: 2
Joined: Sun Sep 27, 2015 3:02 am

Re: MSU1 A/V synchronization

Post by Conn »

Frankly, I don't understand how a satellite radio broadcast could have possibly compensated for different SNES units running at slightly different clock speeds by timing things through NMI, but ... I don't know. Most of the Satellaview service is a mystery to me, given that I've never seen the service live.
If you are interested here's the native code from bszelda:

Code: Select all

$C4/0094 E2 20       SEP #$20                A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0096 AD 90 21    LDA $2190  [$00:2190]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0099 F0 71       BEQ $71    [$010C]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/009B C2 20       REP #$20                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/009D AD 8E 21    LDA $218E  [$00:218E]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/00A0 CF F7 FF 7F CMP $7FFFF7[$7F:FFF7]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/00A4 D0 66       BNE $66    [$010C]      A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/00A6 E2 20       SEP #$20                A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/00A8 AD 93 21    LDA $2193  [$00:2193]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00AB 29 0C       AND #$0C                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00AD D0 51       BNE $51    [$0100]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00AF AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00B2 AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00B5 AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00B8 AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00BB AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00BE AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00C1 C9 01       CMP #$01                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00C3 D0 3B       BNE $3B    [$0100]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00C5 AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00C8 C9 01       CMP #$01                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00CA D0 34       BNE $34    [$0100]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00CC AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00CF 0D 92 21    ORA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00D2 0D 92 21    ORA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00D5 D0 29       BNE $29    [$0100]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00D7 AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00DA AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00DD CF FF FF 7F CMP $7FFFFF[$7F:FFFF]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00E1 F0 03       BEQ $03    [$00E6]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00E3 20 2E 01    JSR $012E  [$00:012E]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00E6 8F FF FF 7F STA $7FFFFF[$7F:FFFF]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00EA AD 92 21    LDA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00ED 8F F9 FF 7F STA $7FFFF9[$7F:FFF9]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00F1 AF FC FF 7F LDA $7FFFFC[$7F:FFFC]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00F5 D0 09       BNE $09    [$0100]      A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00F7 20 2E 01    JSR $012E  [$00:012E]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00FA A9 01       LDA #$01                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/00FC 8F FC FF 7F STA $7FFFFC[$7F:FFFC]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0100 A9 01       LDA #$01                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0102 8D 91 21    STA $2191  [$00:2191]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0105 EA          NOP                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0106 EA          NOP                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0107 EA          NOP                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0108 EA          NOP                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/0109 8D 92 21    STA $2192  [$00:2192]   A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/010C C2 20       REP #$20                A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/010E AF FA FF 7F LDA $7FFFFA[$7F:FFFA]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0112 3A          DEC A                   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0113 D0 13       BNE $13    [$0128]      A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0115 AF FF FF 7F LDA $7FFFFF[$7F:FFFF]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0119 1A          INC A                   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/011A 8F FF FF 7F STA $7FFFFF[$7F:FFFF]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/011E A9 00 00    LDA #$0000              A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0121 8F FC FF 7F STA $7FFFFC[$7F:FFFC]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0125 A9 10 0E    LDA #$0E10              A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0128 8F FA FF 7F STA $7FFFFA[$7F:FFFA]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/012C 28          PLP                     A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/012D 6B          RTL                     A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/012E 48          PHA                     A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/012F C2 20       REP #$20                A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0131 A9 4C 0E    LDA #$0E4C              A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0134 8F FA FF 7F STA $7FFFFA[$7F:FFFA]   A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/0138 E2 20       SEP #$20                A:0000 X:0000 Y:0000 P:EnvmXdIzc
$C4/013A 68          PLA                     A:0000 X:0000 Y:0000 P:EnvMXdIzc
$C4/013B 60          RTS
$7FFFFF is the minute counter, it is increased whenever $7FFFFA gets #$0000. $7FFFFA is the time each minute gets. Usually it gets $C4/0125 A9 10 0E LDA #$0E10 (=3600 nmi cycles, which are countdown:ed every nmi, thus each second has 60 nmi cycles (fps). However at some conditions, which involves the satellaview specific hardware registers $218E-$2192, it also gets $C4/0131 A9 4C 0E LDA #$0E4C (=3660 nmi cycles, 1 second more).
I think this is a code to compensate the timer. For emulation I had to disable this complete code, since the satellaview hardware registers settings seems to be transmitted through satellite.

More info on these satellaview registers can be found here:
http://wiki.superfamicom.org/snes/show/ ... +Registers
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: MSU1 A/V synchronization

Post by Near »

> So, with that sorted out, any opinion on this? viewtopic.php?p=156081#p156081

> $2008-$200b: playback position / seek request in samples (r/w)

I'm not fundamentally opposed to this, I just worry about timing/latency issues.

Let's say someone rigged up a system where the audio tracks were played from an actual CD, or some other strange media, where it's not possible to know the exact current sample. Or there's a latency between the sample the device has read and the sample being piped through the MSU1 to the cartridge connector pins.

This wouldn't be a forward-compatible change any longer, either. With what I've proposed, you can make a game that runs directly in older MSU1 emulators. It simply degrades to not resuming audio, and restarts the track instead. But if we do this, then MSU1.2 games won't run on MSU1.1 emulators unless they go out of their way to test the revision (some may not) and implement MSU1.1 behavior (most probably won't.)
I mean ... probably. I guess if you read and write to non-existent registers, it'll have no effect on the basic resume behavior. But I can imagine people doing more than just audio resume with this. Like having one audio track with multiple samples in it. Sounds stupid, but you give people more flexibility, and they find ways to use it. I've learned that well from my work on cross assemblers. And as you said, there'd probably be attempts to do synchronization tricks by monitoring the sample offsets.

That said, I definitely like the elegance of avoiding the need for two seeks universally, as well as allowing resume for however many tracks you want (up to the limits of RAM you have free in your own game.)

Side note: one crazy idea I've had was to allow multiple instantiations of the MSU1 on the same game under emulation. So you could theoretically have up to 16 channels of audio in $2000-20ff. If we expanded the register count, that would drop to 8 channels. I know this will never be supported on the sd2snes, of course. It'd just be a silly little diversion :D

> Strictly speaking we already have a situation where there's a seek that is supposed to be zero-delay (loop points) so the one seek on resume wouldn't hurt too much in my opinion.

Well ....... yes and no. You're right in the basic implementation, but this is avoided through buffering. As long as you have more samples in a queue than it takes to seek and replenish the buffer samples lost seeking, then when you hit the end of the track, you can seek back and start buffering again.

It definitely does add to the complexity. And indeed, looping wasn't part of MSU1.0 for that reason.

As with clean looping, resume's important, so I'm definitely in favor of getting it in. Just want to make sure we pick the best strategy because it's going to end up set in stone.

There's gotta be a way to resolve that final double-seek (to start over instead of resuming a track) without the need for new registers. I'll keep pondering on that, and then we'll weigh the pros and cons of having a read/write play cursor, let that sit for a while, and then make a decision.

I'll hold off and not put anything in higan v095 so that we have more time to consider it. We can test resume functionality in the v095.01+ WIP releases.
User avatar
ikari_01
Posts: 141
Joined: Sat Jul 04, 2009 2:28 pm
Location: Wunstorf, Germany

Re: MSU1 A/V synchronization

Post by ikari_01 »

byuu wrote:Let's say someone rigged up a system where the audio tracks were played from an actual CD, or some other strange media, where it's not possible to know the exact current sample. Or there's a latency between the sample the device has read and the sample being piped through the MSU1 to the cartridge connector pins.
Same applies to the resume flag. MSU1 still has to figure out where to continue playing so it would need to know the exact (enough) playback position regardless of buffers. If reading is 5s ahead of playback (which would be about the time gap where things BEGIN to matter) you would still need to account for that.
byuu wrote:With what I've proposed, you can make a game that runs directly in older MSU1 emulators.
Well, sort of... you can still make a game that runs in older MSU1 emulators but doesn't properly in newer and vice versa :) (initial volume, DSP mute flag, wav vs pcm, xml vs bml, lax filename specification...)
byuu wrote:Sounds stupid, but you give people more flexibility, and they find ways to use it. I've learned that well from my work on cross assemblers. And as you said, there'd probably be attempts to do synchronization tricks by monitoring the sample offsets.
I agree. But you make it sound as though a means of actual A/V sync were actually a bad thing here. :lol:
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: MSU1 A/V synchronization

Post by Near »

> Same applies to the resume flag.

Well, you have a lot more time then. It's caching something internally, so it won't matter until the same track is requested again, causing another seek event. So the latency between playback and buffering will never be exposed.

Though I suppose as long as we output the sample being given to the SNES cartridge connector rather than the sample position the MSU1 implementation is -actually- reading from (the end of its buffer), it should probably be fine. I'd hate to be wrong about this, and two years later, we find out this change means you can't implement MSU1 using $hardware.

> (initial volume, DSP mute flag, wav vs pcm, xml vs bml, lax filename specification...)

Thankfully, these were all prior to MSU1 really being used. We have three significant things that no longer work:
* Chrono Trigger FMV intro [demo] (21fx API)
* Super Mario Odyssey [single-level demo] (WAV)
* Super Road Blaster [earlier release] (WAV) -> since updated and now compatible again

Believe me, this bothers me more than anyone else. Designing specifications is the hardest thing I've done in life. It's absolutely impossible to divine perfection on your very first try. It's mandatory to get real-world usage data to know what works, what doesn't, and what to improve.

WAV->PCM was because I didn't anticipate people making perfect looping music, and WAV ended up not having a standard way to loop music (there are two non-standard ways to do it, neither of which are well-supported by other players.)

XML->BML was a failure to anticipate the carpal tunnel that would have resulted from trying to dump and manually encode 2100+ games. XML has way too much red tape.

DSP mute flag was due to a lack of knowledge. We never had the ability to stream music to the cartridge pins from our own games until you made the sd2snes. The behavior would still be unemulated if not for you :)

Similarly, UPS->BPS was a failure to consider the poor compression of XOR data, and an over-estimation in the difficulty of delta patch application (creation is still a massive bitch.) And xkas->bass was an under-estimation in how extreme people would get with macros, and a lack of knowledge that all of those special chips were really full-on coprocessors with their own ISAs (hence necessitating the need for a table assembler syntax.)

...

Moving on to file name specification ... I've been working on manifest-free games lately. They are generated dynamically now, which allows the format (XML, BML, etc) and syntax (contents of the files) to change internally within the emulator without breaking anyone's games.

This of course necessitates fixed file names. So going forward, you'll be able to load MSU1 games via:

Code: Select all

Game Name.sfc/
  program.rom
  save.ram [optional]
  msu1.rom [this file being present means MSU1 support should be enabled]
  track-1.pcm
  track-2.pcm ...
Sucks to lose the ability to name tracks intelligently, eg "01 - Opening Theme.pcm"; but I suppose we can include something like "tracks.txt" that is purely for human beings to read.

If you would be willing to support that format with sd2snes, then along with the volume and frequency adjustments you are making, we would have 100% compatibility in our formats :D

(longer-term, I'm planning to make a v073-style UI to get people the hell off that ancient version with its XML and missing MSU1 features.)

I wouldn't expect you to, though. We've made it this far with sd2snes supporting the old game-file approach:

Code: Select all

Game Name.sfc
Game Name.srm [optional]
Game Name.msu
Game Name-1.pcm
Game Name-2.pcm
...

Oh, lastly ... that final hiccup with restarting an audio track causing two seek events ...

If we are willing to rule out the future possibility of more than one resume, then we could simply set the 'resume' flag on the current track when switching to another to erase the resume information on the new track.

Example:
* play track one
*** select track one and play it
* switch to track two (battle music)
*** stop track with save
*** select track two and play it
* A: switch back to track one (with resume)
*** stop track without save
*** select track one and play it
* B: switch back to track one (without resume)
*** stop track with save
*** select track one and play it

This is probably a good idea anyway. Don't want people writing games that rely on N+1 resume slots, and then the game breaks on an implementation with only N resume slots.
User avatar
Ramsis
Posts: 341
Joined: Sun Jul 01, 2012 6:44 am
Location: Lion's den :3
Contact:

Re: MSU1 A/V synchronization

Post by Ramsis »

byuu wrote:We have three significant things that no longer work:
* Chrono Trigger FMV intro [demo] (21fx API)
Ahem. :wink:
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Post Reply