package com.pixelutilitys.arcade.emulators.AEPgb;
/*
JavaBoy
COPYRIGHT (C) 2001 Neil Millstone and The Victoria University of Manchester
;;;
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/** This class can mix a square wave signal with a sound buffer.
* It supports all features of the Gameboys sound channels 1 and 2.
*/
class SquareWaveGenerator {
/** Sound is to be played on the left channel of a stereo sound */
public static final int CHAN_LEFT = 1;
/** Sound is to be played on the right channel of a stereo sound */
public static final int CHAN_RIGHT = 2;
/** Sound is to be played back in mono */
public static final int CHAN_MONO = 4;
/** Length of the sound (in frames) */
int totalLength;
/** Current position in the waveform (in samples) */
int cyclePos;
/** Length of the waveform (in samples) */
int cycleLength;
/** Amplitude of the waveform */
int amplitude;
/** Amount of time the sample stays high in a single waveform (in eighths) */
int dutyCycle;
/** The channel that the sound is to be played back on */
int channel;
/** Sample rate of the sound buffer */
int sampleRate;
/** Initial amplitude */
int initialEnvelope;
/** Number of envelope steps */
int numStepsEnvelope;
/** If true, envelope will increase amplitude of sound, false indicates decrease */
boolean increaseEnvelope;
/** Current position in the envelope */
int counterEnvelope;
/** Frequency of the sound in internal GB format */
int gbFrequency;
/** Amount of time between sweep steps. */
int timeSweep;
/** Number of sweep steps */
int numSweep;
/** If true, sweep will decrease the sound frequency, otherwise, it will increase */
boolean decreaseSweep;
/** Current position in the sweep */
int counterSweep;
/** Create a square wave generator with the supplied parameters */
public SquareWaveGenerator(
int waveLength,
int ampl,
int duty,
int chan,
int rate) {
cycleLength = waveLength;
amplitude = ampl;
cyclePos = 0;
dutyCycle = duty;
channel = chan;
sampleRate = rate;
}
/** Create a square wave generator at the specified sample rate */
public SquareWaveGenerator(int rate) {
dutyCycle = 4;
cyclePos = 0;
channel = CHAN_LEFT | CHAN_RIGHT;
cycleLength = 2;
totalLength = 0;
sampleRate = rate;
amplitude = 32;
counterSweep = 0;
}
/** Set the sound buffer sample rate */
public void setSampleRate(int sr) {
sampleRate = sr;
}
/** Set the duty cycle */
public void setDutyCycle(int duty) {
switch (duty) {
case 0 :
dutyCycle = 1;
break;
case 1 :
dutyCycle = 2;
break;
case 2 :
dutyCycle = 4;
break;
case 3 :
dutyCycle = 6;
break;
}
// System.out.println(dutyCycle);
}
/** Set the sound frequency, in internal GB format */
public void setFrequency(int gbFrequency) {
try {
float frequency = 131072 / 2048;
if (gbFrequency != 2048) {
frequency = ((float) 131072 / (float) (2048 - gbFrequency));
}
// System.out.println("gbFrequency: " + gbFrequency + "");
this.gbFrequency = gbFrequency;
if (frequency != 0) {
cycleLength = (256 * sampleRate) / (int) frequency;
} else {
cycleLength = 65535;
}
if (cycleLength == 0)
cycleLength = 1;
// System.out.println("Cycle length : " + cycleLength + " samples");
} catch (ArithmeticException e) {
// Skip ip
}
}
/** Set the channel for playback */
public void setChannel(int chan) {
channel = chan;
}
/** Set the envelope parameters */
public void setEnvelope(int initialValue, int numSteps, boolean increase) {
initialEnvelope = initialValue;
numStepsEnvelope = numSteps;
increaseEnvelope = increase;
amplitude = initialValue * 2;
}
/** Set the frequency sweep parameters */
public void setSweep(int time, int num, boolean decrease) {
timeSweep = (time + 1) / 2;
numSweep = num;
decreaseSweep = decrease;
counterSweep = 0;
// System.out.println("Sweep: " + time + ", " + num + ", " + decrease);
}
public int getLength() {
return totalLength;
}
public void setLength(int gbLength) {
if (gbLength == -1) {
totalLength = -1;
} else {
totalLength = (64 - gbLength) / 4;
}
}
public void setLength3(int gbLength) {
if (gbLength == -1) {
totalLength = -1;
} else {
totalLength = (256 - gbLength) / 4;
}
}
public void setVolume3(int volume) {
switch (volume) {
case 0 :
amplitude = 0;
break;
case 1 :
amplitude = 32;
break;
case 2 :
amplitude = 16;
break;
case 3 :
amplitude = 8;
break;
}
// System.out.println("A:"+volume);
}
/** Output a frame of sound data into the buffer using the supplied frame length and array offset. */
public void play(byte[] b, int length, int offset) {
int val = 0;
if (totalLength != 0) {
totalLength--;
if (timeSweep != 0) {
counterSweep++;
if (counterSweep > timeSweep) {
if (decreaseSweep) {
setFrequency(gbFrequency - (gbFrequency >> numSweep));
} else {
setFrequency(gbFrequency + (gbFrequency >> numSweep));
}
counterSweep = 0;
}
}
counterEnvelope++;
if (numStepsEnvelope != 0) {
if (((counterEnvelope % numStepsEnvelope) == 0)
&& (amplitude > 0)) {
if (!increaseEnvelope) {
if (amplitude > 0)
amplitude -= 2;
} else {
if (amplitude < 16)
amplitude += 2;
}
}
}
for (int r = offset; r < offset + length; r++) {
if (cycleLength != 0) {
if (((8 * cyclePos) / cycleLength) >= dutyCycle) {
val = amplitude;
} else {
val = -amplitude;
}
}
/* if (cyclePos >= (cycleLength / 2)) {
val = amplitude;
} else {
val = -amplitude;
}*/
if ((channel & CHAN_LEFT) != 0)
b[r * 2] += val;
if ((channel & CHAN_RIGHT) != 0)
b[r * 2 + 1] += val;
if ((channel & CHAN_MONO) != 0)
b[r] += val;
// System.out.print(val + " ");
cyclePos = (cyclePos + 256) % cycleLength;
}
}
}
}