bsnes/higan/gb/apu/noise.cpp

141 lines
3.0 KiB
C++
Raw Normal View History

auto APU::Noise::dacEnable() const -> bool {
return (envelopeVolume || envelopeDirection);
}
auto APU::Noise::getPeriod() const -> uint {
static const uint table[] = {4, 8, 16, 24, 32, 40, 48, 56};
return table[divisor] << frequency;
}
auto APU::Noise::run() -> void {
if(period && --period == 0) {
period = getPeriod();
if(frequency < 14) {
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
lfsr = (lfsr >> 1) ^ (bit << (narrow ? 6 : 14));
}
}
uint4 sample = lfsr & 1 ? 0 : (uint)volume;
if(!enable) sample = 0;
Update to v082r18 release. byuu says: There we go, the GUI is nearly feature-complete once again. All cores now output their native video format (NES={emphasis}{palette}, SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are transformed to RGB555 data that is passed to the video renderer. The video renderer then uses its internal palette to apply brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color space. This does add in another rendering pass, unfortunately, but it's a necessary one for universal support. The plan is to adapt all filters to take RGB555 input, and output RGB555 data as well. By doing this, it will be possible to stack filters. However, it's a bit complicated: I need to plan how the stacking should occur (eg we never want to apply scanlines before HQ2x, etc.) Added input frequency adjustments for all three systems. I can easily get perfect video/audio sync on all three now, hooray. Long-term, it seems like we only really need one, and we can do a video/audio delta to get an adjusted value. But for now, this gets the job done. Added audio volume adjust. I left out the balance for now, since it's obviously impossible to balance the NES' single channel audio (I can duplicate the channel, and do twice the filtering work, but ... why?) I replaced NTSC/PAL TV mode selection with an "Enable Overscan" checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on NES+SNES. Also added aspect correction box back. I don't do that gross PAL distortion shit anymore, sorry PAL people. I just scale up the 54/47*(240/224) aspect correction for overscan off mode. All memory is loaded and saved now, for all three systems (hooray, now you can actually play Zelda 1&2.) Added all of the old bsnes hotkeys, with the exception of capture screenshot. May add again later. May come up with something a bit different for extra features. Re-added the NSS DIP switch setting window. Since geometry is saved, I didn't want to auto-hide rows, so now you'll see all eight possible DIPs, and the ones not used are grayed out. Ultimately, nobody will notice since we only have DIPs for ActRaiser NSS, and nobody's probably even using the XML file for that anyway. Whatever, it's nice to have anyway. Took FitzRoy's advice and single-item combo boxes on the input selection are disabled, so the user doesn't waste time checking them. I wanted to leave text so that you know there's not a problem. Qt disabled radio box items look almost exactly like enabled ones. Fixed lots of issues in phoenix and extended it a bit. But I was still having trouble with radio box grouping, so I said fuck it and made the panels show/hide based instead of append/remove based. That's all for stuff off the checklist, I did a bunch of other things I don't recall. So yeah, I'd say the GUI is 100% usable now. This is my opinion on how multi-platform GUIs should be done =) Oh, I figure I should mention, but the NES core is GPLv3, and all future SNES+GB releases will be as well. It's a move against Microsoft's Metro store.
2011-09-20 14:04:43 +00:00
output = sample;
}
auto APU::Noise::clockLength() -> void {
if(counter) {
if(length && --length == 0) enable = false;
}
}
auto APU::Noise::clockEnvelope() -> void {
if(enable && envelopeFrequency && --envelopePeriod == 0) {
envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8;
if(envelopeDirection == 0 && volume > 0) volume--;
if(envelopeDirection == 1 && volume < 15) volume++;
}
}
auto APU::Noise::read(uint16 addr) -> uint8 {
if(addr == 0xff1f) { //NR40
return 0xff;
}
if(addr == 0xff20) { //NR41
return 0xff;
}
if(addr == 0xff21) { //NR42
return envelopeVolume << 4 | envelopeDirection << 3 | envelopeFrequency;
}
if(addr == 0xff22) { //NR43
return frequency << 4 | narrow << 3 | divisor;
}
if(addr == 0xff23) { //NR44
return 0x80 | counter << 6 | 0x3f;
}
return 0xff;
}
auto APU::Noise::write(uint16 addr, uint8 data) -> void {
if(addr == 0xff20) { //NR41
length = 64 - (data & 0x3f);
}
if(addr == 0xff21) { //NR42
envelopeVolume = data.bits(7,4);
envelopeDirection = data.bit (3);
envelopeFrequency = data.bits(2,0);
if(!dacEnable()) enable = false;
}
if(addr == 0xff22) { //NR43
frequency = data.bits(7,4);
narrow = data.bit (3);
divisor = data.bits(2,0);
period = getPeriod();
}
if(addr == 0xff23) { //NR44
if((apu.phase & 1) && !counter && (data & 0x40)) {
if(length && --length == 0) enable = false;
}
counter = data.bit(6);
if(data.bit(7)) {
enable = dacEnable();
lfsr = -1;
envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8;
volume = envelopeVolume;
if(!length) {
length = 64;
if(apu.phase.bit(0) && counter) length--;
}
}
}
}
auto APU::Noise::power(bool initializeLength) -> void {
enable = 0;
envelopeVolume = 0;
envelopeDirection = 0;
envelopeFrequency = 0;
frequency = 0;
narrow = 0;
divisor = 0;
counter = 0;
output = 0;
envelopePeriod = 0;
volume = 0;
period = 0;
lfsr = 0;
if(initializeLength) length = 64;
}
auto APU::Noise::serialize(serializer& s) -> void {
s.integer(enable);
s.integer(envelopeVolume);
s.integer(envelopeDirection);
s.integer(envelopeFrequency);
s.integer(frequency);
s.integer(narrow);
s.integer(divisor);
s.integer(counter);
s.integer(output);
s.integer(length);
s.integer(envelopePeriod);
s.integer(volume);
s.integer(period);
s.integer(lfsr);
}