/* Copyright © 2011 Chris Spencer <email@example.com>
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 3 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, see <http://www.gnu.org/licenses/>. */
//! GameBoy sound output emulator.
friend class GbMemory;
//! Constructor; sets the associated emulator container.
//! Resets the sound emulator to its default state.
//! Generates a single sample.
* The base class implementation does nothing except return the number of CPU cycles that should
* be executed before poll() is called again.
virtual double poll();
//! Checks for and handles any events then returns.
* The base class implementation does nothing.
virtual void pollEvents();
//! Sets the callback function to be called at the given frequency based on the audio clock.
* There is no guarantee that the callback will be called exactly at the given frequency or at
* consistent intervals. It will however average to the requested frequency and will be suitable
* for generating sound data at exactly the same rate as the audio system requires it.
* The callback may be called in any thread and it should not block.
virtual void setTimerCallback(double frequency, boost::function<void ()> callback) = 0;
//! Handles a write to a sound register.
void writeIoPort(uint8_t ptr, uint8_t val);
//! Resets all the sound registers to their initial states.
void resetRegisters(GbMemory &mem) const;
//! Starts recording to the given file.
* This does nothing if already recording.
void record(const boost::filesystem::path &path);
//! Stops recording.
* This does nothing if recording is not active.
//! Saves the current state of the sound emulator into the given message.
void save(GbSoundData &data) const;
//! Loads the sound emulator state from the given message.
void load(const GbSoundData &data);
// Values of registers that are persisted across power cycles
// File into which the generated sound is saved, if enabled
// Sample rate of the audio device
// The number of CPU cycles per audio sample
// Current frequency in GameBoy format
uint16_t gbFrequency1_, gbFrequency2_, gbFrequency3_;
// Current frequency in Hz
double actFrequency1_, actFrequency2_, actFrequency3_, actFrequency4_;
// Whether the square wave is currently in the high or low part
bool hi1_, hi2_;
// Remaining playback duration
double duration1_, duration2_, duration3_, duration4_;
// Wave pattern duty
double duty1_, duty2_;
// Number of samples before toggling the high or low part of the square wave
double countdown1_, countdown2_, countdown3_, countdown4_;
// Whether the sweep shift is enabled
// The next frequency that will be played in the sweep
// Amount the frequency is shifted by at each sweep shift
// Type of shift. 0 = addition, 1 = subtraction
// Number of samples between sweep shifts
// Number of samples to next sweep shift
// Current envelope state
uint8_t envelope1_, envelope2_, envelope4_;
// Direction of the envelope sweep. 0 = decrease, 1 = increase
bool envelopeDirection1_, envelopeDirection2_, envelopeDirection4_;
// Number of samples between envelope steps
double envelopeStep1_, envelopeStep2_, envelopeStep4_;
// Number of samples to the next envelope step
double envelopeCountdown1_, envelopeCountdown2_, envelopeCountdown4_;
// Current half-byte index into wavePattern3_
// Wave pattern for sound mode 3
// Output level for sound mode 3 (i.e., number of bits to shift right by)
// The counter stage selected for sound channel 4. This points to either lfsr7 or lfsr15 in
const uint32_t *counterData4_;
// Size of the counterData4_ array
// Current index into the LFSR counter array
// Adjusts the given envelope parameters
void adjustEnvelope(uint8_t &envelope, bool envelopeDirection, double envelopeStep,
// Functions for each of the sound modes. The output is mixed in the main poll() function
// Generates a single sample
void generateSample(double &left, double &right);
// Performs the channel 1 sweep
// Adds the given channel amplitude to the appropriate output channels based on the value of the
// control bits
void doChannel(double amplitude, uint8_t bit, double &left, double &right);
// Disabled operations
GbSound(const GbSound &);
GbSound & operator=(const GbSound &);