mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r17 release.
byuu says: Emulated GBC sound plus the new extensions to it. I am kind of surprised by how little developers utilized the GBC audio portion. Mr. Driller now has sound effects, and Pinobee no Daibouken has BGM. I still have yet to emulate the GBA extra sound channels and PWM. Need to emulate timers and DMA 2 refresh mode before I can do that. Also, I moved both GBC and GBA audio to use length = data; if(++length == 0); rather than length = 64 - data; if(--length == 0); so that I could return literal values for register reads. I thought there was a good reason we used the latter version, but I can't hear any audible difference even in GBC games, so oh well. Lastly, I think the pattern[++offset] in the wave channel was a bug in the DMG/GBC only. I really, really hope it doesn't apply to the GBA, because that will make bank selection a serious pain in the ass.
This commit is contained in:
parent
b8d0ec29b2
commit
1de484262c
|
@ -1,7 +1,7 @@
|
||||||
#ifndef BASE_HPP
|
#ifndef BASE_HPP
|
||||||
#define BASE_HPP
|
#define BASE_HPP
|
||||||
|
|
||||||
static const char Version[] = "087.16";
|
static const char Version[] = "087.17";
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
#include <nall/platform.hpp>
|
||||||
#include <nall/algorithm.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
|
|
|
@ -20,8 +20,11 @@ void APU::Noise::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APU::Noise::clock_length() {
|
void APU::Noise::clock_length() {
|
||||||
if(counter && length) {
|
//if(counter && length) {
|
||||||
if(--length == 0) enable = false;
|
// if(--length == 0) enable = false;
|
||||||
|
//}
|
||||||
|
if(enable && counter) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +38,8 @@ void APU::Noise::clock_envelope() {
|
||||||
|
|
||||||
void APU::Noise::write(unsigned r, uint8 data) {
|
void APU::Noise::write(unsigned r, uint8 data) {
|
||||||
if(r == 1) { //$ff20 NR41
|
if(r == 1) { //$ff20 NR41
|
||||||
length = 64 - (data & 0x3f);
|
//length = 64 - (data & 0x3f);
|
||||||
|
length = data & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff21 NR42
|
if(r == 2) { //$ff21 NR42
|
||||||
|
@ -62,7 +66,7 @@ void APU::Noise::write(unsigned r, uint8 data) {
|
||||||
lfsr = ~0U;
|
lfsr = ~0U;
|
||||||
envelope_period = envelope_frequency;
|
envelope_period = envelope_frequency;
|
||||||
volume = envelope_volume;
|
volume = envelope_volume;
|
||||||
if(length == 0) length = 64;
|
//if(length == 0) length = 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct Noise {
|
||||||
bool counter;
|
bool counter;
|
||||||
|
|
||||||
int16 output;
|
int16 output;
|
||||||
unsigned length;
|
uint6 length;
|
||||||
uint3 envelope_period;
|
uint3 envelope_period;
|
||||||
uint4 volume;
|
uint4 volume;
|
||||||
unsigned period;
|
unsigned period;
|
||||||
|
|
|
@ -39,8 +39,12 @@ void APU::Square1::sweep(bool update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APU::Square1::clock_length() {
|
void APU::Square1::clock_length() {
|
||||||
if(counter && length) {
|
//if(counter && length) {
|
||||||
if(--length == 0) enable = false;
|
// if(--length == 0) enable = false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if(counter && enable) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +74,8 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
||||||
|
|
||||||
if(r == 1) { //$ff11 NR11
|
if(r == 1) { //$ff11 NR11
|
||||||
duty = data >> 6;
|
duty = data >> 6;
|
||||||
length = 64 - (data & 0x3f);
|
//length = 64 - (data & 0x3f);
|
||||||
|
length = data & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff12 NR12
|
if(r == 2) { //$ff12 NR12
|
||||||
|
@ -98,7 +103,7 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
||||||
sweep_enable = sweep_period || sweep_shift;
|
sweep_enable = sweep_period || sweep_shift;
|
||||||
sweep_negate = false;
|
sweep_negate = false;
|
||||||
if(sweep_shift) sweep(0);
|
if(sweep_shift) sweep(0);
|
||||||
if(length == 0) length = 64;
|
//if(length == 0) length = 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ struct Square1 {
|
||||||
uint3 sweep_shift;
|
uint3 sweep_shift;
|
||||||
bool sweep_negate;
|
bool sweep_negate;
|
||||||
uint2 duty;
|
uint2 duty;
|
||||||
unsigned length;
|
uint6 length;
|
||||||
uint4 envelope_volume;
|
uint4 envelope_volume;
|
||||||
bool envelope_direction;
|
bool envelope_direction;
|
||||||
uint3 envelope_frequency;
|
uint3 envelope_frequency;
|
||||||
|
|
|
@ -23,8 +23,12 @@ void APU::Square2::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APU::Square2::clock_length() {
|
void APU::Square2::clock_length() {
|
||||||
if(counter && length) {
|
//if(counter && length) {
|
||||||
if(--length == 0) enable = false;
|
// if(--length == 0) enable = false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if(counter && enable) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +43,8 @@ void APU::Square2::clock_envelope() {
|
||||||
void APU::Square2::write(unsigned r, uint8 data) {
|
void APU::Square2::write(unsigned r, uint8 data) {
|
||||||
if(r == 1) { //$ff16 NR21
|
if(r == 1) { //$ff16 NR21
|
||||||
duty = data >> 6;
|
duty = data >> 6;
|
||||||
length = 64 - (data & 0x3f);
|
//length = 64 - (data & 0x3f);
|
||||||
|
length = (data & 0x3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff17 NR22
|
if(r == 2) { //$ff17 NR22
|
||||||
|
@ -62,7 +67,7 @@ void APU::Square2::write(unsigned r, uint8 data) {
|
||||||
enable = dac_enable();
|
enable = dac_enable();
|
||||||
envelope_period = envelope_frequency;
|
envelope_period = envelope_frequency;
|
||||||
volume = envelope_volume;
|
volume = envelope_volume;
|
||||||
if(length == 0) length = 64;
|
//if(length == 0) length = 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ struct Square2 {
|
||||||
bool enable;
|
bool enable;
|
||||||
|
|
||||||
uint2 duty;
|
uint2 duty;
|
||||||
unsigned length;
|
uint6 length;
|
||||||
uint4 envelope_volume;
|
uint4 envelope_volume;
|
||||||
bool envelope_direction;
|
bool envelope_direction;
|
||||||
uint3 envelope_frequency;
|
uint3 envelope_frequency;
|
||||||
|
|
|
@ -13,8 +13,11 @@ void APU::Wave::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APU::Wave::clock_length() {
|
void APU::Wave::clock_length() {
|
||||||
if(counter && length) {
|
//if(counter && length) {
|
||||||
if(--length == 0) enable = false;
|
// if(--length == 0) enable = false;
|
||||||
|
//}
|
||||||
|
if(enable && counter) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +28,8 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 1) { //$ff1b NR31
|
if(r == 1) { //$ff1b NR31
|
||||||
length = 256 - data;
|
//length = 256 - data;
|
||||||
|
length = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r == 2) { //$ff1c NR32
|
if(r == 2) { //$ff1c NR32
|
||||||
|
@ -49,7 +53,7 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
||||||
if(initialize) {
|
if(initialize) {
|
||||||
enable = dac_enable;
|
enable = dac_enable;
|
||||||
pattern_offset = 0;
|
pattern_offset = 0;
|
||||||
if(length == 0) length = 256;
|
//if(length == 0) length = 256;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct Wave {
|
||||||
uint8 pattern[32];
|
uint8 pattern[32];
|
||||||
|
|
||||||
int16 output;
|
int16 output;
|
||||||
unsigned length;
|
uint8 length;
|
||||||
unsigned period;
|
unsigned period;
|
||||||
uint5 pattern_offset;
|
uint5 pattern_offset;
|
||||||
uint4 pattern_sample;
|
uint4 pattern_sample;
|
||||||
|
|
|
@ -4,14 +4,21 @@ namespace GBA {
|
||||||
|
|
||||||
#include "registers.cpp"
|
#include "registers.cpp"
|
||||||
#include "mmio.cpp"
|
#include "mmio.cpp"
|
||||||
|
#include "square.cpp"
|
||||||
|
#include "square1.cpp"
|
||||||
|
#include "square2.cpp"
|
||||||
|
#include "wave.cpp"
|
||||||
|
#include "noise.cpp"
|
||||||
|
#include "sequencer.cpp"
|
||||||
APU apu;
|
APU apu;
|
||||||
|
|
||||||
void APU::Enter() { apu.enter(); }
|
void APU::Enter() { apu.enter(); }
|
||||||
|
|
||||||
void APU::enter() {
|
void APU::enter() {
|
||||||
while(true) {
|
while(true) {
|
||||||
interface->audioSample(0, 0);
|
runsequencer();
|
||||||
step(512);
|
interface->audioSample(sequencer.lsample, sequencer.rsample);
|
||||||
|
step(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +30,12 @@ void APU::step(unsigned clocks) {
|
||||||
void APU::power() {
|
void APU::power() {
|
||||||
create(APU::Enter, 16777216);
|
create(APU::Enter, 16777216);
|
||||||
|
|
||||||
|
square1.power();
|
||||||
|
square2.power();
|
||||||
|
wave.power();
|
||||||
|
noise.power();
|
||||||
|
sequencer.power();
|
||||||
|
|
||||||
regs.bias = 0x0200;
|
regs.bias = 0x0200;
|
||||||
|
|
||||||
for(unsigned n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this;
|
for(unsigned n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this;
|
||||||
|
|
|
@ -8,6 +8,8 @@ struct APU : Thread, MMIO {
|
||||||
uint8 read(uint32 addr);
|
uint8 read(uint32 addr);
|
||||||
void write(uint32 addr, uint8 byte);
|
void write(uint32 addr, uint8 byte);
|
||||||
void power();
|
void power();
|
||||||
|
|
||||||
|
void runsequencer();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern APU apu;
|
extern APU apu;
|
||||||
|
|
|
@ -1,10 +1,90 @@
|
||||||
uint8 APU::read(uint32 addr) {
|
uint8 APU::read(uint32 addr) {
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
|
||||||
|
//NR10
|
||||||
|
case 0x04000060: return square1.read(0);
|
||||||
|
case 0x04000061: return 0u;
|
||||||
|
|
||||||
|
//NR11 + NR12
|
||||||
|
case 0x04000062: return square1.read(1);
|
||||||
|
case 0x04000063: return square1.read(2);
|
||||||
|
|
||||||
|
//NR13 + NR14
|
||||||
|
case 0x04000064: return square1.read(3);
|
||||||
|
case 0x04000065: return square1.read(4);
|
||||||
|
|
||||||
|
//NR21 + NR22
|
||||||
|
case 0x04000068: return square2.read(1);
|
||||||
|
case 0x04000069: return square2.read(2);
|
||||||
|
|
||||||
|
//NR23 + NR24
|
||||||
|
case 0x0400006c: return square2.read(3);
|
||||||
|
case 0x0400006d: return square2.read(4);
|
||||||
|
|
||||||
|
//NR30
|
||||||
|
case 0x04000070: return wave.read(0);
|
||||||
|
case 0x04000071: return 0u;
|
||||||
|
|
||||||
|
//NR31 + NR32
|
||||||
|
case 0x04000072: return wave.read(1);
|
||||||
|
case 0x04000073: return wave.read(2);
|
||||||
|
|
||||||
|
//NR33 + NR34
|
||||||
|
case 0x04000074: return wave.read(3);
|
||||||
|
case 0x04000075: return wave.read(4);
|
||||||
|
|
||||||
|
//NR41 + NR42
|
||||||
|
case 0x04000078: return noise.read(1);
|
||||||
|
case 0x04000079: return noise.read(2);
|
||||||
|
|
||||||
|
//NR43 + NR44
|
||||||
|
case 0x0400007c: return noise.read(3);
|
||||||
|
case 0x0400007d: return noise.read(4);
|
||||||
|
|
||||||
|
//NR50 + NR51
|
||||||
|
case 0x04000080: return sequencer.read(0);
|
||||||
|
case 0x04000081: return sequencer.read(1);
|
||||||
|
|
||||||
|
//NR52
|
||||||
|
case 0x04000084: return sequencer.read(2);
|
||||||
|
case 0x04000085: return 0u;
|
||||||
|
|
||||||
//SOUNDBIAS
|
//SOUNDBIAS
|
||||||
case 0x04000088: return regs.bias >> 0;
|
case 0x04000088: return regs.bias >> 0;
|
||||||
case 0x04000089: return regs.bias >> 8;
|
case 0x04000089: return regs.bias >> 8;
|
||||||
|
|
||||||
|
//WAVE_RAM0_L
|
||||||
|
case 0x04000090: return wave.readram( 0);
|
||||||
|
case 0x04000091: return wave.readram( 1);
|
||||||
|
|
||||||
|
//WAVE_RAM0_H
|
||||||
|
case 0x04000092: return wave.readram( 2);
|
||||||
|
case 0x04000093: return wave.readram( 3);
|
||||||
|
|
||||||
|
//WAVE_RAM1_L
|
||||||
|
case 0x04000094: return wave.readram( 4);
|
||||||
|
case 0x04000095: return wave.readram( 5);
|
||||||
|
|
||||||
|
//WAVE_RAM1_H
|
||||||
|
case 0x04000096: return wave.readram( 6);
|
||||||
|
case 0x04000097: return wave.readram( 7);
|
||||||
|
|
||||||
|
//WAVE_RAM2_L
|
||||||
|
case 0x04000098: return wave.readram( 8);
|
||||||
|
case 0x04000099: return wave.readram( 9);
|
||||||
|
|
||||||
|
//WAVE_RAM2_H
|
||||||
|
case 0x0400009a: return wave.readram(10);
|
||||||
|
case 0x0400009b: return wave.readram(11);
|
||||||
|
|
||||||
|
//WAVE_RAM3_L
|
||||||
|
case 0x0400009c: return wave.readram(12);
|
||||||
|
case 0x0400009d: return wave.readram(13);
|
||||||
|
|
||||||
|
//WAVE_RAM3_H
|
||||||
|
case 0x0400009e: return wave.readram(14);
|
||||||
|
case 0x0400009f: return wave.readram(15);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0u;
|
return 0u;
|
||||||
|
@ -13,6 +93,90 @@ uint8 APU::read(uint32 addr) {
|
||||||
void APU::write(uint32 addr, uint8 byte) {
|
void APU::write(uint32 addr, uint8 byte) {
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
|
||||||
|
//NR10
|
||||||
|
case 0x04000060: return square1.write(0, byte);
|
||||||
|
case 0x04000061: return;
|
||||||
|
|
||||||
|
//NR11 + NR12
|
||||||
|
case 0x04000062: return square1.write(1, byte);
|
||||||
|
case 0x04000063: return square1.write(2, byte);
|
||||||
|
|
||||||
|
//NR13 + NR14
|
||||||
|
case 0x04000064: return square1.write(3, byte);
|
||||||
|
case 0x04000065: return square1.write(4, byte);
|
||||||
|
|
||||||
|
//NR21 + NR22
|
||||||
|
case 0x04000068: return square2.write(1, byte);
|
||||||
|
case 0x04000069: return square2.write(2, byte);
|
||||||
|
|
||||||
|
//NR23 + NR24
|
||||||
|
case 0x0400006c: return square2.write(3, byte);
|
||||||
|
case 0x0400006d: return square2.write(4, byte);
|
||||||
|
|
||||||
|
//NR30
|
||||||
|
case 0x04000070: return wave.write(0, byte);
|
||||||
|
case 0x04000071: return;
|
||||||
|
|
||||||
|
//NR31 + NR32
|
||||||
|
case 0x04000072: return wave.write(1, byte);
|
||||||
|
case 0x04000073: return wave.write(2, byte);
|
||||||
|
|
||||||
|
//NR33 + NR34
|
||||||
|
case 0x04000074: return wave.write(3, byte);
|
||||||
|
case 0x04000075: return wave.write(4, byte);
|
||||||
|
|
||||||
|
//NR41 + NR42
|
||||||
|
case 0x04000078: return noise.write(1, byte);
|
||||||
|
case 0x04000079: return noise.write(2, byte);
|
||||||
|
|
||||||
|
//NR43 + NR44
|
||||||
|
case 0x0400007c: return noise.write(3, byte);
|
||||||
|
case 0x0400007d: return noise.write(4, byte);
|
||||||
|
|
||||||
|
//NR50 + NR51
|
||||||
|
case 0x04000080: return sequencer.write(0, byte);
|
||||||
|
case 0x04000081: return sequencer.write(1, byte);
|
||||||
|
|
||||||
|
//SOUND_CNT_H
|
||||||
|
case 0x04000082: return;
|
||||||
|
case 0x04000083: return;
|
||||||
|
|
||||||
|
//NR52
|
||||||
|
case 0x04000084: return sequencer.write(2, byte);
|
||||||
|
case 0x04000085: return;
|
||||||
|
|
||||||
|
//WAVE_RAM0_L
|
||||||
|
case 0x04000090: return wave.writeram( 0, byte);
|
||||||
|
case 0x04000091: return wave.writeram( 1, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM0_H
|
||||||
|
case 0x04000092: return wave.writeram( 2, byte);
|
||||||
|
case 0x04000093: return wave.writeram( 3, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM1_L
|
||||||
|
case 0x04000094: return wave.writeram( 4, byte);
|
||||||
|
case 0x04000095: return wave.writeram( 5, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM1_H
|
||||||
|
case 0x04000096: return wave.writeram( 6, byte);
|
||||||
|
case 0x04000097: return wave.writeram( 7, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM2_L
|
||||||
|
case 0x04000098: return wave.writeram( 8, byte);
|
||||||
|
case 0x04000099: return wave.writeram( 9, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM2_H
|
||||||
|
case 0x0400009a: return wave.writeram(10, byte);
|
||||||
|
case 0x0400009b: return wave.writeram(11, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM3_L
|
||||||
|
case 0x0400009c: return wave.writeram(12, byte);
|
||||||
|
case 0x0400009d: return wave.writeram(13, byte);
|
||||||
|
|
||||||
|
//WAVE_RAM3_H
|
||||||
|
case 0x0400009e: return wave.writeram(14, byte);
|
||||||
|
case 0x0400009f: return wave.writeram(15, byte);
|
||||||
|
|
||||||
//SOUNDBIAS
|
//SOUNDBIAS
|
||||||
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return;
|
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return;
|
||||||
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return;
|
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return;
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
unsigned APU::Noise::divider() const {
|
||||||
|
if(divisor == 0) return 8;
|
||||||
|
return divisor * 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Noise::run() {
|
||||||
|
if(period && --period == 0) {
|
||||||
|
period = divider() << frequency;
|
||||||
|
if(frequency < 14) {
|
||||||
|
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
||||||
|
lfsr = (lfsr >> 1) ^ (bit << (narrowlfsr ? 6 : 14));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output = volume;
|
||||||
|
if(enable == false || (lfsr & 1)) output = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Noise::clocklength() {
|
||||||
|
if(enable && counter) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Noise::clockenvelope() {
|
||||||
|
if(enable && envelope.frequency && --envelope.period == 0) {
|
||||||
|
envelope.period = envelope.frequency;
|
||||||
|
if(envelope.direction == 0 && volume > 0) volume--;
|
||||||
|
if(envelope.direction == 1 && volume < 15) volume++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 APU::Noise::read(unsigned addr) const {
|
||||||
|
switch(addr) {
|
||||||
|
case 1: return (length << 0);
|
||||||
|
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||||
|
case 3: return (divisor << 0) | (narrowlfsr << 3) | (frequency << 4);
|
||||||
|
case 4: return (counter << 6) | (initialize << 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Noise::write(unsigned addr, uint8 byte) {
|
||||||
|
switch(addr) {
|
||||||
|
case 1: //NR41
|
||||||
|
length = byte >> 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //NR42
|
||||||
|
envelope.frequency = byte >> 0;
|
||||||
|
envelope.direction = byte >> 3;
|
||||||
|
envelope.volume = byte >> 4;
|
||||||
|
if(envelope.dacenable() == false) enable = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: //NR43
|
||||||
|
divisor = byte >> 0;
|
||||||
|
narrowlfsr = byte >> 3;
|
||||||
|
frequency = byte >> 4;
|
||||||
|
period = divider() << frequency;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: //NR44
|
||||||
|
counter = byte >> 6;
|
||||||
|
initialize = byte >> 7;
|
||||||
|
|
||||||
|
if(initialize) {
|
||||||
|
enable = envelope.dacenable();
|
||||||
|
lfsr = ~0u;
|
||||||
|
envelope.period = envelope.frequency;
|
||||||
|
volume = envelope.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Noise::power() {
|
||||||
|
envelope.frequency = 0;
|
||||||
|
envelope.direction = 0;
|
||||||
|
envelope.volume = 0;
|
||||||
|
envelope.period = 0;
|
||||||
|
length = 0;
|
||||||
|
divisor = 0;
|
||||||
|
narrowlfsr = 0;
|
||||||
|
frequency = 0;
|
||||||
|
counter = 0;
|
||||||
|
initialize = 0;
|
||||||
|
enable = 0;
|
||||||
|
lfsr = 0;
|
||||||
|
output = 0;
|
||||||
|
period = 0;
|
||||||
|
volume = 0;
|
||||||
|
}
|
|
@ -8,3 +8,130 @@ struct Registers {
|
||||||
SoundBias& operator=(const SoundBias&) = delete;
|
SoundBias& operator=(const SoundBias&) = delete;
|
||||||
} bias;
|
} bias;
|
||||||
} regs;
|
} regs;
|
||||||
|
|
||||||
|
struct Sweep {
|
||||||
|
uint3 shift;
|
||||||
|
uint1 direction;
|
||||||
|
uint3 frequency;
|
||||||
|
|
||||||
|
uint1 enable;
|
||||||
|
uint1 negate;
|
||||||
|
uint3 period;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Envelope {
|
||||||
|
uint3 frequency;
|
||||||
|
uint1 direction;
|
||||||
|
uint4 volume;
|
||||||
|
|
||||||
|
uint3 period;
|
||||||
|
|
||||||
|
inline bool dacenable() const { return volume || direction; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Square {
|
||||||
|
Envelope envelope;
|
||||||
|
uint1 enable;
|
||||||
|
uint6 length;
|
||||||
|
uint2 duty;
|
||||||
|
uint11 frequency;
|
||||||
|
uint1 counter;
|
||||||
|
uint1 initialize;
|
||||||
|
|
||||||
|
signed shadowfrequency;
|
||||||
|
uint1 signal;
|
||||||
|
uint4 output;
|
||||||
|
unsigned period;
|
||||||
|
uint3 phase;
|
||||||
|
uint4 volume;
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void clocklength();
|
||||||
|
void clockenvelope();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Square1 : Square {
|
||||||
|
Sweep sweep;
|
||||||
|
|
||||||
|
void runsweep(bool update);
|
||||||
|
void clocksweep();
|
||||||
|
uint8 read(unsigned addr) const;
|
||||||
|
void write(unsigned addr, uint8 byte);
|
||||||
|
void power();
|
||||||
|
} square1;
|
||||||
|
|
||||||
|
struct Square2 : Square {
|
||||||
|
uint8 read(unsigned addr) const;
|
||||||
|
void write(unsigned addr, uint8 byte);
|
||||||
|
void power();
|
||||||
|
} square2;
|
||||||
|
|
||||||
|
struct Wave {
|
||||||
|
uint1 mode;
|
||||||
|
uint1 bank;
|
||||||
|
uint1 dacenable;
|
||||||
|
uint8 length;
|
||||||
|
uint3 volume;
|
||||||
|
uint11 frequency;
|
||||||
|
uint1 counter;
|
||||||
|
uint1 initialize;
|
||||||
|
uint4 pattern[32];
|
||||||
|
|
||||||
|
uint1 enable;
|
||||||
|
uint4 output;
|
||||||
|
uint4 patternaddr;
|
||||||
|
uint1 patternbank;
|
||||||
|
uint4 patternsample;
|
||||||
|
unsigned period;
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void clocklength();
|
||||||
|
uint8 read(unsigned addr) const;
|
||||||
|
void write(unsigned addr, uint8 byte);
|
||||||
|
uint8 readram(unsigned addr) const;
|
||||||
|
void writeram(unsigned addr, uint8 byte);
|
||||||
|
void power();
|
||||||
|
} wave;
|
||||||
|
|
||||||
|
struct Noise {
|
||||||
|
Envelope envelope;
|
||||||
|
uint6 length;
|
||||||
|
uint3 divisor;
|
||||||
|
uint1 narrowlfsr;
|
||||||
|
uint4 frequency;
|
||||||
|
uint1 counter;
|
||||||
|
uint1 initialize;
|
||||||
|
|
||||||
|
uint1 enable;
|
||||||
|
uint15 lfsr;
|
||||||
|
uint4 output;
|
||||||
|
unsigned period;
|
||||||
|
uint4 volume;
|
||||||
|
|
||||||
|
unsigned divider() const;
|
||||||
|
void run();
|
||||||
|
void clocklength();
|
||||||
|
void clockenvelope();
|
||||||
|
uint8 read(unsigned addr) const;
|
||||||
|
void write(unsigned addr, uint8 byte);
|
||||||
|
void power();
|
||||||
|
} noise;
|
||||||
|
|
||||||
|
struct Sequencer {
|
||||||
|
uint3 lvolume;
|
||||||
|
uint3 rvolume;
|
||||||
|
uint1 lenable[4];
|
||||||
|
uint1 renable[4];
|
||||||
|
uint1 enable[4];
|
||||||
|
uint1 masterenable;
|
||||||
|
|
||||||
|
uint13 base;
|
||||||
|
uint3 step;
|
||||||
|
int16 lsample;
|
||||||
|
int16 rsample;
|
||||||
|
|
||||||
|
signed volumeadjust(signed sample, uint3 volume);
|
||||||
|
uint8 read(unsigned addr) const;
|
||||||
|
void write(unsigned addr, uint8 byte);
|
||||||
|
void power();
|
||||||
|
} sequencer;
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
void APU::runsequencer() {
|
||||||
|
auto &r = sequencer;
|
||||||
|
|
||||||
|
if(r.base == 0) { //512hz
|
||||||
|
if(r.step == 0 || r.step == 2 || r.step == 4 || r.step == 6) { //256hz
|
||||||
|
square1.clocklength();
|
||||||
|
square2.clocklength();
|
||||||
|
wave.clocklength();
|
||||||
|
noise.clocklength();
|
||||||
|
}
|
||||||
|
if(r.step == 2 || r.step == 6) { //128hz
|
||||||
|
square1.clocksweep();
|
||||||
|
}
|
||||||
|
if(r.step == 7) { //64hz
|
||||||
|
square1.clockenvelope();
|
||||||
|
square2.clockenvelope();
|
||||||
|
noise.clockenvelope();
|
||||||
|
}
|
||||||
|
r.step++;
|
||||||
|
}
|
||||||
|
r.base++;
|
||||||
|
|
||||||
|
if(r.enable[0]) square1.run();
|
||||||
|
if(r.enable[1]) square2.run();
|
||||||
|
if(r.enable[2]) wave.run();
|
||||||
|
if(r.enable[3]) noise.run();
|
||||||
|
|
||||||
|
signed lsample = 0;
|
||||||
|
if(r.lenable[0]) lsample += square1.output;
|
||||||
|
if(r.lenable[1]) lsample += square2.output;
|
||||||
|
if(r.lenable[2]) lsample += wave.output;
|
||||||
|
if(r.lenable[3]) lsample += noise.output;
|
||||||
|
lsample = (lsample * 512) - 15360;
|
||||||
|
lsample = r.volumeadjust(lsample, r.lvolume);
|
||||||
|
r.lsample = lsample;
|
||||||
|
|
||||||
|
signed rsample = 0;
|
||||||
|
if(r.renable[0]) rsample += square1.output;
|
||||||
|
if(r.renable[1]) rsample += square2.output;
|
||||||
|
if(r.renable[2]) rsample += wave.output;
|
||||||
|
if(r.renable[3]) rsample += noise.output;
|
||||||
|
rsample = (rsample * 512) - 15360;
|
||||||
|
rsample = r.volumeadjust(rsample, r.rvolume);
|
||||||
|
r.rsample = rsample;
|
||||||
|
|
||||||
|
if(r.masterenable == false) {
|
||||||
|
r.lsample = 0;
|
||||||
|
r.rsample = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signed APU::Sequencer::volumeadjust(signed sample, uint3 volume) {
|
||||||
|
switch(volume) {
|
||||||
|
case 0: return (sample >> 3); // 12.5%
|
||||||
|
case 1: return (sample >> 2); // 25.0%
|
||||||
|
case 2: return (sample >> 2) + (sample >> 3); // 37.5%
|
||||||
|
case 3: return (sample >> 1); // 50.0%
|
||||||
|
case 4: return (sample >> 1) + (sample >> 3); // 62.5%
|
||||||
|
case 5: return (sample >> 0) - (sample >> 2); // 75.0%
|
||||||
|
case 6: return (sample >> 0) - (sample >> 3); // 87.5%
|
||||||
|
case 7: return (sample >> 0); //100.0%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 APU::Sequencer::read(unsigned addr) const {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: return (rvolume << 0) | (lvolume << 4);
|
||||||
|
case 1: return (
|
||||||
|
(renable[0] << 0)
|
||||||
|
| (renable[1] << 1)
|
||||||
|
| (renable[2] << 2)
|
||||||
|
| (renable[3] << 3)
|
||||||
|
| (lenable[0] << 4)
|
||||||
|
| (lenable[1] << 5)
|
||||||
|
| (lenable[2] << 6)
|
||||||
|
| (lenable[3] << 7)
|
||||||
|
);
|
||||||
|
case 2: return (
|
||||||
|
(enable[0] << 0)
|
||||||
|
| (enable[1] << 1)
|
||||||
|
| (enable[2] << 2)
|
||||||
|
| (enable[3] << 3)
|
||||||
|
| (masterenable << 7)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Sequencer::write(unsigned addr, uint8 byte) {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: //NR50
|
||||||
|
rvolume = byte >> 0;
|
||||||
|
lvolume = byte >> 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: //NR51
|
||||||
|
renable[0] = byte >> 0;
|
||||||
|
renable[1] = byte >> 1;
|
||||||
|
renable[2] = byte >> 2;
|
||||||
|
renable[3] = byte >> 3;
|
||||||
|
lenable[0] = byte >> 4;
|
||||||
|
lenable[1] = byte >> 5;
|
||||||
|
lenable[2] = byte >> 6;
|
||||||
|
lenable[3] = byte >> 7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //NR52
|
||||||
|
enable[0] = byte >> 0;
|
||||||
|
enable[1] = byte >> 1;
|
||||||
|
enable[2] = byte >> 2;
|
||||||
|
enable[3] = byte >> 3;
|
||||||
|
masterenable = byte >> 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Sequencer::power() {
|
||||||
|
lvolume = 0;
|
||||||
|
rvolume = 0;
|
||||||
|
for(auto &n : lenable) n = 0;
|
||||||
|
for(auto &n : renable) n = 0;
|
||||||
|
for(auto &n : enable) n = 0;
|
||||||
|
masterenable = 0;
|
||||||
|
base = 0;
|
||||||
|
step = 0;
|
||||||
|
lsample = 0;
|
||||||
|
rsample = 0;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
void APU::Square::run() {
|
||||||
|
if(period && --period == 0) {
|
||||||
|
period = 4 * (2048 - frequency);
|
||||||
|
phase++;
|
||||||
|
switch(duty) {
|
||||||
|
case 0: signal = (phase == 6); break; //_____-_
|
||||||
|
case 1: signal = (phase >= 6); break; //______--
|
||||||
|
case 2: signal = (phase >= 4); break; //____----
|
||||||
|
case 3: signal = (phase <= 5); break; //------__
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint4 sample = volume;
|
||||||
|
if(enable == false || signal == false) sample = 0;
|
||||||
|
output = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square::clocklength() {
|
||||||
|
if(enable && counter) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square::clockenvelope() {
|
||||||
|
if(enable && envelope.frequency && --envelope.period == 0) {
|
||||||
|
envelope.period = envelope.frequency;
|
||||||
|
if(envelope.direction == 0 && volume > 0) volume--;
|
||||||
|
if(envelope.direction == 1 && volume < 15) volume++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
void APU::Square1::runsweep(bool update) {
|
||||||
|
if(sweep.enable == false) return;
|
||||||
|
|
||||||
|
sweep.negate = sweep.direction;
|
||||||
|
unsigned delta = shadowfrequency >> sweep.shift;
|
||||||
|
signed updatefrequency = shadowfrequency + (sweep.negate ? -delta : delta);
|
||||||
|
|
||||||
|
if(updatefrequency > 2047) {
|
||||||
|
enable = false;
|
||||||
|
} else if(sweep.shift && update) {
|
||||||
|
shadowfrequency = updatefrequency;
|
||||||
|
frequency = updatefrequency;
|
||||||
|
period = 4 * (2048 - frequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square1::clocksweep() {
|
||||||
|
if(enable && sweep.frequency && --sweep.period == 0) {
|
||||||
|
sweep.period = sweep.frequency;
|
||||||
|
runsweep(1);
|
||||||
|
runsweep(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 APU::Square1::read(unsigned addr) const {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: return (sweep.shift << 0) | (sweep.direction << 3) | (sweep.frequency << 4);
|
||||||
|
case 1: return (length << 0) | (duty << 6);
|
||||||
|
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||||
|
case 3: return (frequency << 0);
|
||||||
|
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square1::write(unsigned addr, uint8 byte) {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: //NR10
|
||||||
|
if(sweep.negate && sweep.direction && !(byte & 0x08)) enable = false;
|
||||||
|
sweep.shift = byte >> 0;
|
||||||
|
sweep.direction = byte >> 3;
|
||||||
|
sweep.frequency = byte >> 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: //NR11
|
||||||
|
length = byte >> 0;
|
||||||
|
duty = byte >> 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //NR12
|
||||||
|
envelope.frequency = byte >> 0;
|
||||||
|
envelope.direction = byte >> 3;
|
||||||
|
envelope.volume = byte >> 4;
|
||||||
|
if(envelope.dacenable() == false) enable = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: //NR13
|
||||||
|
frequency = (frequency & 0xff00) | (byte << 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: //NR14
|
||||||
|
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||||
|
counter = byte >> 6;
|
||||||
|
initialize = byte >> 7;
|
||||||
|
|
||||||
|
if(initialize) {
|
||||||
|
enable = envelope.dacenable();
|
||||||
|
envelope.period = envelope.frequency;
|
||||||
|
volume = envelope.volume;
|
||||||
|
shadowfrequency = frequency;
|
||||||
|
sweep.period = sweep.frequency;
|
||||||
|
sweep.enable = sweep.period || sweep.shift;
|
||||||
|
sweep.negate = false;
|
||||||
|
if(sweep.shift) runsweep(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
period = 4 * (2048 - frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square1::power() {
|
||||||
|
envelope.frequency = 0;
|
||||||
|
envelope.direction = 0;
|
||||||
|
envelope.direction = 0;
|
||||||
|
envelope.period = 0;
|
||||||
|
sweep.shift = 0;
|
||||||
|
sweep.direction = 0;
|
||||||
|
sweep.frequency = 0;
|
||||||
|
sweep.enable = 0;
|
||||||
|
sweep.negate = 0;
|
||||||
|
sweep.period = 0;
|
||||||
|
enable = 0;
|
||||||
|
length = 0;
|
||||||
|
duty = 0;
|
||||||
|
frequency = 0;
|
||||||
|
counter = 0;
|
||||||
|
initialize = 0;
|
||||||
|
shadowfrequency = 0;
|
||||||
|
signal = 0;
|
||||||
|
output = 0;
|
||||||
|
period = 0;
|
||||||
|
phase = 0;
|
||||||
|
volume = 0;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
uint8 APU::Square2::read(unsigned addr) const {
|
||||||
|
switch(addr) {
|
||||||
|
case 1: return (length << 0) | (duty << 6);
|
||||||
|
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||||
|
case 3: return (frequency >> 0);
|
||||||
|
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square2::write(unsigned addr, uint8 byte) {
|
||||||
|
switch(addr) {
|
||||||
|
case 1: //NR21
|
||||||
|
length = byte >> 0;
|
||||||
|
duty = byte >> 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //NR22
|
||||||
|
envelope.frequency = byte >> 0;
|
||||||
|
envelope.direction = byte >> 3;
|
||||||
|
envelope.volume = byte >> 4;
|
||||||
|
if(envelope.dacenable() == false) enable = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: //NR23
|
||||||
|
frequency = (frequency & 0xff00) | (byte << 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: //NR24
|
||||||
|
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||||
|
counter = byte >> 6;
|
||||||
|
initialize = byte >> 7;
|
||||||
|
|
||||||
|
if(initialize) {
|
||||||
|
enable = envelope.dacenable();
|
||||||
|
envelope.period = envelope.frequency;
|
||||||
|
volume = envelope.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
period = 4 * (2048 - frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Square2::power() {
|
||||||
|
envelope.frequency = 0;
|
||||||
|
envelope.direction = 0;
|
||||||
|
envelope.direction = 0;
|
||||||
|
envelope.period = 0;
|
||||||
|
enable = 0;
|
||||||
|
length = 0;
|
||||||
|
duty = 0;
|
||||||
|
frequency = 0;
|
||||||
|
counter = 0;
|
||||||
|
initialize = 0;
|
||||||
|
shadowfrequency = 0;
|
||||||
|
signal = 0;
|
||||||
|
output = 0;
|
||||||
|
period = 0;
|
||||||
|
phase = 0;
|
||||||
|
volume = 0;
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
void APU::Wave::run() {
|
||||||
|
if(period && --period == 0) {
|
||||||
|
period = 2 * (2048 - frequency);
|
||||||
|
patternsample = pattern[patternbank * 16 + patternaddr++];
|
||||||
|
if(patternaddr == 0) patternbank ^= mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = patternsample;
|
||||||
|
switch(volume) {
|
||||||
|
case 0: output = 0; // 0%
|
||||||
|
case 1: break; //100%
|
||||||
|
case 2: output >>= 1; // 50%
|
||||||
|
case 3: output >>= 2; // 25%
|
||||||
|
case 4: output -= output >> 2; // 75%
|
||||||
|
case 5: output -= output >> 2; // 75%
|
||||||
|
case 6: output -= output >> 2; // 75%
|
||||||
|
case 7: output -= output >> 2; // 75%
|
||||||
|
}
|
||||||
|
if(enable == false) output = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Wave::clocklength() {
|
||||||
|
if(enable && counter) {
|
||||||
|
if(++length == 0) enable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 APU::Wave::read(unsigned addr) const {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: return (mode << 5) | (bank << 6) | (dacenable << 7);
|
||||||
|
case 1: return (length << 0);
|
||||||
|
case 2: return (volume << 5);
|
||||||
|
case 3: return (frequency >> 0);
|
||||||
|
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Wave::write(unsigned addr, uint8 byte) {
|
||||||
|
switch(addr) {
|
||||||
|
case 0: //NR30
|
||||||
|
mode = byte >> 5;
|
||||||
|
bank = byte >> 6;
|
||||||
|
dacenable = byte >> 7;
|
||||||
|
if(dacenable == false) enable = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: //NR31
|
||||||
|
length = byte >> 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //NR32
|
||||||
|
volume = byte >> 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: //NR33
|
||||||
|
frequency = (frequency & 0xff00) | (byte << 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: //NR34
|
||||||
|
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||||
|
counter = byte >> 6;
|
||||||
|
initialize = byte >> 7;
|
||||||
|
|
||||||
|
if(initialize) {
|
||||||
|
enable = dacenable;
|
||||||
|
patternaddr = 0;
|
||||||
|
patternbank = mode ? (uint1)0 : bank;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
period = 2 * (2048 - frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 APU::Wave::readram(unsigned addr) const {
|
||||||
|
uint8 byte = 0;
|
||||||
|
byte |= pattern[addr * 2 + 0] << 0;
|
||||||
|
byte |= pattern[addr * 2 + 1] << 4;
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Wave::writeram(unsigned addr, uint8 byte) {
|
||||||
|
pattern[addr * 2 + 0] = byte >> 0;
|
||||||
|
pattern[addr * 2 + 1] = byte >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::Wave::power() {
|
||||||
|
mode = 0;
|
||||||
|
bank = 0;
|
||||||
|
dacenable = 0;
|
||||||
|
length = 0;
|
||||||
|
volume = 0;
|
||||||
|
frequency = 0;
|
||||||
|
counter = 0;
|
||||||
|
initialize = 0;
|
||||||
|
for(auto &sample : pattern) sample = 0;
|
||||||
|
enable = 0;
|
||||||
|
output = 0;
|
||||||
|
patternaddr = 0;
|
||||||
|
patternbank = 0;
|
||||||
|
patternsample = 0;
|
||||||
|
period = 0;
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ Config::Config() {
|
||||||
append(audio.frequencyNES = 1789772, "Audio::Frequency::NES");
|
append(audio.frequencyNES = 1789772, "Audio::Frequency::NES");
|
||||||
append(audio.frequencySNES = 32000, "Audio::Frequency::SNES");
|
append(audio.frequencySNES = 32000, "Audio::Frequency::SNES");
|
||||||
append(audio.frequencyGB = 4194304, "Audio::Frequency::GB");
|
append(audio.frequencyGB = 4194304, "Audio::Frequency::GB");
|
||||||
append(audio.frequencyGBA = 32768, "Audio::Frequency::GBA");
|
append(audio.frequencyGBA = 4194304, "Audio::Frequency::GBA");
|
||||||
|
|
||||||
append(input.driver = "", "Input::Driver");
|
append(input.driver = "", "Input::Driver");
|
||||||
append(input.focusPolicy = 1, "Input::FocusPolicy");
|
append(input.focusPolicy = 1, "Input::FocusPolicy");
|
||||||
|
|
|
@ -70,8 +70,8 @@ AudioSettings::AudioSettings() {
|
||||||
|
|
||||||
gba.name.setText("GBA:");
|
gba.name.setText("GBA:");
|
||||||
gba.slider.setLength(2001);
|
gba.slider.setLength(2001);
|
||||||
gba.base = 32768;
|
gba.base = 4194304;
|
||||||
gba.step = 1;
|
gba.step = 131;
|
||||||
|
|
||||||
append(title, { ~0, 0 }, 5);
|
append(title, { ~0, 0 }, 5);
|
||||||
append(outputLabel, { ~0, 0 }, 0);
|
append(outputLabel, { ~0, 0 }, 0);
|
||||||
|
|
Loading…
Reference in New Issue