/*
* HalfNES by Andrew Hoffman
* Licensed under the GNU GPL Version 3. See LICENSE file
*/
package com.grapeshot.halfnes.audio;
import com.grapeshot.halfnes.utils;
/**
*
* @author Andrew
*/
public class VRC6SoundChip implements ExpansionSoundChip {
//to access sound test in Castlevania 3(J) -
//Hold down A+B while resetting, push Start twice
private final Timer[] timers = {new SquareTimer(16), new SquareTimer(16)};
private final boolean[] enable = {true, true, true};
private final int[] volume = {0, 0, 0};
private int sawdivider = 15;
private int sawctr = 0;
private int sawaccum = 0;
private int sawseq = 0;
private boolean clocknow = false;
@Override
public final void write(final int register, final int data) {
switch (register) {
case 0x9000:
volume[0] = data & 0xf;
//duty cycle is between 12.5% and 50% unless last bit set and then it's forced to 100%
timers[0].setduty(((data & (utils.BIT7)) != 0) ? 16 : (((data >> 4) & 7) + 1));
break;
case 0x9001:
timers[0].setperiod((timers[0].getperiod() & 0xf00) + data);
break;
case 0x9002:
timers[0].setperiod((timers[0].getperiod() & 0xff) + ((data & 0xf) << 8));
enable[0] = ((data & (utils.BIT7)) != 0);
break;
case 0xa000:
volume[1] = data & 0xf;
timers[1].setduty(((data & (utils.BIT7)) != 0) ? 16 : (((data >> 4) & 7) + 1));
break;
case 0xa001:
timers[1].setperiod((timers[1].getperiod() & 0xf00) + data);
break;
case 0xa002:
timers[1].setperiod((timers[1].getperiod() & 0xff) + ((data & 0xf) << 8));
enable[1] = ((data & (utils.BIT7)) != 0);
break;
case 0xb000:
//saw accumulator
sawaccum = data & 0x3f;
break;
case 0xb001:
sawdivider &= 0xf00;
sawdivider += data;
break;
case 0xb002:
sawdivider &= 0xff;
sawdivider += ((data & 0xf) << 8);
enable[2] = ((data & (utils.BIT7)) != 0);
break;
}
}
@Override
public final void clock(final int cycle) {
timers[0].clock(cycle);
timers[1].clock(cycle);
for (int i = 0; i < cycle; ++i) {
clocksaw();
}
}
@Override
public final int getval() {
return 320 * (((enable[0] ? volume[0] : 0) * timers[0].getval()
+ (enable[1] ? volume[1] : 0) * timers[1].getval())
+ (enable[2] ? ((volume[2] & 0xff) >> 3) : 0));
}
private void clocksaw() {
--sawctr;
if (sawctr < 0) {
sawctr = sawdivider;
if (clocknow) {
clocknow = false;
volume[2] += sawaccum;
++sawseq;
if (sawseq > 6) {
sawseq = 0;
volume[2] = 0;
}
} else {
clocknow = true;
}
}
}
}