/*
    Namco custom waveform sound generator 3 (Pacman hardware)

    Copyright (c) 2003,2004 Alessandro Scotti
    http://www.ascotti.org/

    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
*/
#ifndef NAMCO_WSG3_H_
#define NAMCO_WSG3_H_

/**
    Namco 3-channel sound generator voice properties.    

    This information is only needed by applications that want to do their own
    sound rendering, as the playSound() function already plays and mixes all
    three voices.

    @see PacmanMachine::playSound
*/
struct NamcoWsg3Voice
{
    /** Volume (from 0 to 15) */
    unsigned volume;
    /** Index into the 4-bit 32-entry waveform table (0 to 7) */
    unsigned waveform; 
    /** Frequency */
    unsigned frequency;

    /** Default constructor */
    NamcoWsg3Voice() : volume(0), waveform(0), frequency(0) {
    }

    /** Returns true if the voice is active, false otherwise. */
    int isActive() const {
        return (volume > 0) && (frequency > 0);
    }
};

/**
*/
class NamcoWsg3
{
public:
    /**
        Constructor.

        @param masterClock clock frequency of sound chip (in Hertz)
        @param samplingRate sampling rate of the generated sound

        @see #playSound
    */
    NamcoWsg3( unsigned masterClock );
    
    /**
        Destructor.
    */
    virtual ~NamcoWsg3() {
    }

    /**
        Sets the 256 byte PROM that contains the waveform table used by the sound chip.
    */
    void setSoundPROM( const unsigned char * prom );

    /**
        Returns the 256 byte PROM with waveform data info for the sound
        generator.
    */
    const unsigned char * getSoundROM() const {
        return sound_prom_;
    }

    /**
        Sets the value of the specified register.
    */
    void setRegister( unsigned reg, unsigned char value ) {
        sound_regs_[reg] = value;
    }

    /**
        Returns the value of the specified register.
    */
    unsigned char getRegister( unsigned reg ) const {
        return sound_regs_[reg];
    }

    /**
        Reproduces the sound that is currently being generated by the sound
        chip into the specified buffer.

        The sound chip has three independent voices that generate 8-bit signed
        PCM audio. This function resamples the voices at the currently specified
        sampling rate and mixes them into the output buffer. The output buffer
        can be converted to 8-bit (signed) PCM by dividing each sample by 3 (since 
        there are three voices) or it can be expanded to 16-bit by multiplying
        each sample by 85 (i.e. 256 divided by 3). If necessary, it is possible
        to approximate these values with 4 and 64 in order to use arithmetic
        shifts that are usually faster to execute.

        Note: this function does not clear the content of the output buffer before
        mixing voices into it.

        @param buf pointer to sound buffer that receives the audio samples
        @param len length of the sound buffer
    */
    void playSound( int * buf, int len );

    /**
        Returns a pointer to a structure describing the current status of the
        specified voice in the sound generator. 
        
        This is only useful if the application wants to reproduce the sound by
        itself, as the playSound() function already transforms and mixes all
        sound voices in a format useable by an application.

        @param voice structure to receive voice information
        @param index voice index (0, 1 or 2)

        @see #playSound
    */
    void getVoice( NamcoWsg3Voice * voice, int index ) const;

    /**
        Sets the output sampling rate for playSound().

        @param samplingRate sampling rate in Hertz (samples per second)
    */
    void setSamplingRate( unsigned samplingRate ) {
        sampling_rate_ = samplingRate;
        // Compute the resampling increment, in fixed point
        // format with 10 bits for decimals
        resample_step_ = samplingRate ? (master_clock_ << 10) / samplingRate : 0;
    }

    /**
        Returns the sampling rate currently in use for rendering sound.
    */
    unsigned getSamplingRate() const {
        return sampling_rate_;
    }

    /** 
        Returns the size of the buffer needed to take a snapshot of the sound chip.
        
        @see PacmanMachine::getSizeOfSnapshotBuffer
    */
    unsigned getSizeOfSnapshotBuffer() const;

    /**         
        Takes a snapshot of the sound chip.

        A snapshot saves the chip registers and the wave PROM.

        Note: the size of the snapshot buffer must be no less than the size
        returned by the getSizeOfSnapshotBuffer() function.

        @param buffer buffer where the snapshot data is stored

        @return the number of bytes written into the buffer

        @see PacmanMachine::takeSnapshot
        @see MsPacmanMachine::takeSnapshot
    */
    unsigned takeSnapshot( unsigned char * buffer );

    /**
        Restores a snapshot taken with takeSnapshot().

        This function uses the data saved in the snapshot buffer to restore the
        sound chip status.

        @param buffer buffer where the snapshot data is stored

        @return the number of bytes read from the buffer

        @see PacmanMachine::restoreSnapshot
        @see MsPacmanMachine::restoreSnapshot
    */
    unsigned restoreSnapshot( unsigned char * buffer );

private:
    unsigned        master_clock_;          // Master clock of sound chip
    unsigned        sampling_rate_;         // Sampling rate for generated sound
    unsigned char   sound_regs_[0x20];      // Sound registers
    unsigned char   sound_prom_[32*8];      // Sound chip wavetable PROM
    // Internal variable for faster sound generation
    unsigned        resample_step_;
    unsigned        wave_offset_[3];        // Current sample offset (for each voice)
    int             sound_wave_data_[32*8]; // Wave data for sound generation
};

#endif // NAMCO_WSG3_H_
