Page 8 of 14

Re: Bad Apple demo for SNES

Posted: Mon Feb 02, 2015 5:42 pm
by tepples
DMA registers are readable, or blargg's serial code wouldn't work.

When you build the nametable and hit a $80-$BF opcode, where are you storing the number of the next unique tile? I'm just trying to decide what advantage I could have for 11000000 over 110000bb bbbbbbbb.

Re: Bad Apple demo for SNES

Posted: Mon Feb 02, 2015 7:17 pm
by psycopathicteen
Where are you storing the number of the next unique tile?
Address $004322

Re: Bad Apple demo for SNES

Posted: Mon Feb 02, 2015 7:59 pm
by tepples
So the program can predict the number of tiles to decompress from the number of the last unique tile in the nametable. I have been maintaining a test decompressor for each format change to test the compressor, and it just uses the 110000xx xxxxxxxx end mark as an assertion of byte stream consistency.

Here's the data in the agreed format. It still leaves enough space for mono BRR at 16 kHz.

Re: Bad Apple demo for SNES

Posted: Mon Feb 02, 2015 8:51 pm
by psycopathicteen
What frame does the first chunk end on?

Re: Bad Apple demo for SNES

Posted: Tue Feb 03, 2015 6:48 am
by tepples
I believe there are 4292 frames in the first chunk.

Re: Bad Apple demo for SNES

Posted: Wed Feb 04, 2015 2:59 am
by 93143
My high-frequency enhancement scheme seems promising. I've isolated highpassed samples for the crash, hi-hat, kick(/snare?), s, k, t, and ch/j. The crash is nearly 14 kB, which is more than half the total, but it loops nicely. The BRR compression results in a very high broadband noise floor - only 25 dB below the signal peak in the case of the crash - but there's enough going on in the main body of the track that a bit of extra noise doesn't really stand out.

Here's a comparison of the first few beats with and without the enhancement. The main track is at 16 kHz, and the crash/hat/drum are at 32 kHz; all components have been separately passed through BRRTools. Mix positions for the samples were chosen by eye at moderate zoom, to rule out unreasonable precision requirements.
hifreq_comparison.rar
(127.21 KiB) Downloaded 187 times
I'd kinda like to be able to do the squiggly synth sound that sometimes accompanies the crash at the beginning of a section, but it's very difficult to isolate and I don't believe in my ability to reconstruct it from scratch (I'm not a synth guy)...

Unfortunately, I looped the crash cymbal before attempting any sort of compensation for rolloff, so I will probably have to do it again...

...

Speaking of which: I copied this filter into Matlab and got the attached plot.

1) Is this what it's supposed to look like? It's been a while since I studied digital controls and signal processing... (The x-axis is actually Hz, not rad/s...)

2) If this is right, are the peak and high-frequency falloff part of the intended behaviour, or are they artifacts of the fitting method (ie: would the ideal curve keep going up)? What does the function it's supposed to be compensating for look like? What sort of error magnitudes should I expect from this?
trans.png
Also, I've noted that when filtering the track through BRRTools, using -g for both encoding and decoding results in a much duller sound than not using it for either, to the point of sounding noticeably worse when enhanced. (The material in the example was not pre- or post-filtered).

Re: Bad Apple demo for SNES

Posted: Wed Feb 04, 2015 1:34 pm
by psycopathicteen
Now it always crashes during the fire part for some reason. I tried tracing it in the debugger, and it looks like the CPU gets screwed up hitting a #$ff byte that is not supposed to be there, and it ends up doing 768 tile patterns, which overflows from one frame buffer to another. I'll try overwriting it to make it with #$c0, and see if that fixes it.

Re: Bad Apple demo for SNES

Posted: Wed Feb 04, 2015 8:50 pm
by tepples
I have identified a problem in my encoder where a completely white frame would register as -1 tiles instead of 0 tiles. Internally in my encoder, $0000 is the all-white tile, $0001 is the all-black tile, and pattern tiles start at $0002. In any frame, the number of pattern tiles is equal to the maximum tile number in the image minus 1. For example, if the highest tile number is 295, there are 296 tiles, of which all but the first two are encoded, for a pattern table length of 294 tiles. This assumption fails for all-white frames such as frame 2707 (2727 in the original video; mine trims 20 leading black frames).

The fix is to edit all $FFFF pattern table length words to $C000. I have fixed my encoder and tested the fix.

93143: The preemph filter I made for that post is a symmetric FIR filter, and all symmetric FIR filters are linear phase. Try graphing it with linear frequency, not log frequency. The function it's compensating for is the "4-point Gaussian interpolation" in Fullsnes. The peak and high-frequency rolloff are an artifact of using only 15 taps; an ideal filter would continue up to +11 dB.

Re: Bad Apple demo for SNES

Posted: Thu Feb 05, 2015 7:29 am
by kp64
Brilliant , Fantastic , really impresive!
Cant wait to see ( or hear) the demo with sound :D .
psycopathicteen , tepples and 93143 , you are reallly skilled , thank you.
I hope that , some far away day, I can be close to that level of ability.

I tested the ROM on my SNES:
PAL , CPU: 02 , PPU: 01 , PPU: 02
Powerpack , firmware v2.02.
It works without any problem , but a 17% slower.

Re: Bad Apple demo for SNES

Posted: Thu Feb 05, 2015 11:41 pm
by 93143
Okay, I implemented the interpolator in Matlab, and it looks like it works. It's hard to get an accurate picture of what's going on with non-integer resampling factors, because the FFTs no longer map nicely and the curve obtained by subtracting the power spectra gets buried in noise. (I suppose I could try a moving average...) But from just plotting the power spectra on top of each other, it does seem like the behaviour is fairly consistent.

Consistent, but not frequency-independent. If my code is right, even after correcting for input sample rate there's a bit of extra rolloff on 16 kHz data.

EDIT: I tried a moving average. The 22.05 kHz case tracks the 16 kHz one. Just so we're clear, this plot is normalized to the Nyquist frequency for the input data.
snesgain_norm.png
I guess now I have a pretty good idea of what needs to be done to the audio before it's converted. EDIT: Got some settings figured out in PLParEQ3, for both 16 kHz and 32 kHz. On white noise, using the equalizer followed by the gaussian results in +/-0.2 dB of ripple in the top end for both cases, which is more than good enough.

...

Who's writing the audio engine for this thing? I haven't accidentally volunteered myself, have I?

Re: Bad Apple demo for SNES

Posted: Fri Feb 06, 2015 3:00 pm
by psycopathicteen
I'm waiting for Tepples to post the fixed version of the compression data.

Re: Bad Apple demo for SNES

Posted: Fri Feb 06, 2015 4:48 pm
by tepples
This any better?

Re: Bad Apple demo for SNES

Posted: Fri Feb 06, 2015 11:42 pm
by 93143
Well, I may be jumping the gun a little with this exercise, but I've converted the samples. Attached (in case anyone cares at this point) are BRRs of the crash cymbal, hi-hat, snare/kick, ch, k, sh, and t. IIRC the k and t were taken from around 5:00-5:01 in the long version, and the ch and sh are from 2:01 and 2:17 respectively. The crash is from 0:13 (heavily processed of course), and the hat and snare are from somewhere before that.
basamples_v1.rar
(27.06 KiB) Downloaded 190 times
The volume of the samples has not been altered (except incidentally via prefiltering), so they will have to be taken down a bit to fit the streaming audio. When I put a 16 kHz mono version of the original track through my custom prefilter, the peak amplitude went up by nearly 5 dB.

[The BRR compression really does a number on this stuff... kinda makes me wonder if it's worth all the precision I put in the front end...]

...

I don't get the same results from my gaussian interpolator as from BRRTools with -g turned on. And it's not a small difference; using -g instead of my version makes the whole high-frequency augmentation scheme not work very well. I'd think I did it wrong, but the curve I get at 32 kHz matches tepples' description (plus, tepples' filter is in BRRTools, and as I said before, using -g for both encoding and decoding muffles the output). So I looked at the source code for BRRTools and found this:

Code: Select all

void apply_gauss_filter(pcm_t *buffer, size_t length)
{
	int prev = (372  + 1034) * buffer[0] + 372 * buffer[1];		// First sample
	for(unsigned int i=1; i < length-1; ++i)
	{
		int k0 = 372 * (buffer[i-1] + buffer[i+1]);
		int k = 1034 * buffer[i];
		buffer[i-1] = prev/2048;
		prev = k0 + k;
	}
	int last = 372 * buffer[length-2] + (1034 + 372) * buffer[length-1];
	buffer[length-2] = prev/2048;
	buffer[length-1] = last/2048;
}
This doesn't look at all like what anomie and nocash describe. It just looks like a symmetric smoothing filter with gain reduction. Did I miss something? What's going on here?

Re: Bad Apple demo for SNES

Posted: Sat Feb 07, 2015 12:34 am
by tepples
Under the nocash stuff, a Gaussian interpolation aligned to sample boundary will produce [$176, $519, $172]/2048 which is [374, 1305, 370]/2048 which slightly exceeds unity gain at DC. I normalized this in my own BRR decoder to [372, 1304, 372]/2048, which incidentally is very close to [2, 7, 2]/11.

What apply_gauss_filter appears to be doing is convolving with [372, 1034, 372]/2048. I think there's a bit of a typo going on here (1034 when 1304 is intended), and this is causing the muffling you're hearing.

Is source code for your prefilter available?

Re: Bad Apple demo for SNES

Posted: Sat Feb 07, 2015 1:28 am
by 93143
I should have looked closer when I saw that "/2048"...

Source code for the prefilter? No, unfortunately. I'm using PLParEQ3, a cut-down version of PLParEQ which is apparently not available any more. The full version seems to be in the "if you have to ask, you can't afford it" category, which is a far cry from the $20 I got my copy for back when they were fishing for donations. I can post the settings for 16 and 32 kHz if you like, but I imagine a more general (and portable) formulation would have been more useful...

I did test my scheme on white noise, following up with my implementation of the 4-point interpolator, and the result was +/-0.2 dB of ripple versus the original spectrum. And I can't hear a difference, not in the brightness at least. So unless my interpolator is wrong, or I made a really weird error somewhere else, I'd say the prefiltering is doing what it's supposed to.

Here's the interpolator, in Matlab (a bit of a lazy hack, but aside from the phase alignment it should be okay):

Code: Select all

function X32 = gsnes(Xin,Fs);

gausstable;

X = Xin;
X(end+1:end+3) = Xin(1:3);

p = floor(4096*Fs/32000);
pcount = 0;
S = 4;
i = 0;

X32 = zeros(floor(length(Xin)*32000/Fs),1);
if mod(length(X32),2),
    X32(end+1) = 0;
end
for I = 1:length(X32),
    X32(I) = (gtable(256-i)*X(S-3)/1024 + ...
              gtable(512-i)*X(S-2)/1024 + ...
              gtable(257+i)*X(S-1)/1024 + ...
              gtable(1+i)*X(S)/1024)/2;
    pcount = pcount + p;
    S = 4 + floor(pcount/4096);
    i = floor(pcount/16) - floor(pcount/4096)*256;
end
The gausstable macro just defines gtable; it's essentially a copy/paste of the table in fullsnes with a bunch of "hex2dec" syntax inserted. I see no point in reproducing it here.