/*
 * ____ DAPHNE COPYRIGHT NOTICE ____
 *
 * Copyright (C) 2001 Matt Ownby
 *
 * This file is part of DAPHNE, a laserdisc arcade game emulator
 *
 * DAPHNE 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.
 *
 * DAPHNE 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 SOUND_H
#define SOUND_H

#include <SDL3/SDL.h>

// header file for sound.c

namespace sound
{
// max # of samples any game can handle (make this number as small as possible)
static const uint16_t MAX_NUM = 50;
// frequency all our audio runs at.
// In order to change this value, all .wav's and .ogg's will need to be
// resampled, which
//  is quite involved. Other parts of the code may assume the frequency is 44100
//  too (such as ldp-vldp-audio.cpp)
static const uint16_t FREQ = 44100;
// stereo sound
static const uint16_t CHANNELS = 2;
// stereo, 16-bit sound has 4 bytes per sample
static const uint16_t BYTES_PER_SAMPLE = 4;
// volume for each stream can be between 0-64
// (keep this as a power of 2, see MAX_VOL_POWER)
static const uint16_t MAX_VOLUME = 64;
// if 2^MAX_VOL_POWER = MAX_VOLUME
static const uint16_t MAX_VOL_POWER = 6;
// SDL audio format (16-bit signed, little endian)
// This is true even for big-endian platforms
static const SDL_AudioFormat FORMAT = SDL_AUDIO_S16;

// how many audio bytes needed to fill 1 millisecond of space
static const unsigned int G_1MS_BUF_SIZE = (FREQ * BYTES_PER_SAMPLE) / 1000;

enum {
    CHIP_UNDEFINED,
    CHIP_SAMPLES,
    CHIP_VLDP,
    CHIP_SN76496,
    CHIP_AY_3_8910,
    CHIP_PC_BEEPER,
    CHIP_DAC,
    CHIP_TONEGEN
};

struct sample_s {
    // how many channels (1 = mono, 2 = stereo) that this sample has
    unsigned int uChannels;

    // length of the sample ...
    unsigned int uLength;

    // the sample's buffer
    Uint8 *pu8Buf;
};

// macro to do 16-bit clipping
#define DO_CLIP(i)                                                             \
    if (i > 32767) {                                                           \
        i = 32767;                                                             \
    } else if (i < -32768) {                                                   \
        i = -32768;                                                            \
    }

struct chip {
    // *** THIS SECTION IS DEFINED INTERNALLY
    // IMPORTANT: buffer and next_soundchip MUST come first, because they must
    // match
    //  the structure mix_s defined in mix.h; this is so we can use our MMX
    //  optimized
    //  audio mixing function.
    Uint8 *buffer;     // pointer to buffer used by this sound chip
    struct chip *next; // pointer to the next sound chip in this
                       // linked list

    Uint8 *buffer_pointer; // pointer to where we are in the buffer
    Uint32 bytes_left;     // number of bytes left in buffer
    unsigned int id; // used so game drivers can call audio_writedata (if there
                     // are multiple sound chips being used)
    int internal_id; // internal ID that the sound chips returns when
                     // init_callback is called
    unsigned int uVolume[CHANNELS]; // don't modify this value directly,
                                    // use set_soundchip_volume() to do it
                                    // ...

    // This is the volume that the game driver has requested (if no request,
    // this is MAX_VOLUME).
    // It is not affected by set_soundchip_volume.  uVolume is calculated based
    // on this value.
    unsigned int uDriverVolume[CHANNELS];

    // This is the volume that the user has requested (if no request, this is
    // MAX_VOLUME).
    // It is not affected by set_soundchip_volume.  uVolume is calculated based
    // on this value.
    unsigned int uBaseVolume[CHANNELS];

    // callback to initialize the sound chip.
    // The callback returns an internal ID which is used in all the other
    // callbacks to
    //  refer to the sound chip that has been created.
    // On success a number >= 0 will be returned. If there is an error, -1 will
    // be returned.
    int (*init_callback)(Uint32 freq_hz);
    void (*shutdown_callback)(int internal_id); // callback to shutdown the
                                                // sound chip
    void (*writedata_callback)(Uint8 data, int internal_id); // callback to
                                                             // write data to
                                                             // the sound chip

    // optional callback for those sound chips that take a 'ctrl' byte to write
    // 'data' to,
    //  such as the PC beeper which writes data to specific ports.  It's up to
    //  the game driver
    //  to decide whether to use this callback or not.
    // NOTE : the arguments are unsigned int's for speed, but they usually will
    // probably be Uint8's
    void (*write_ctrl_data_callback)(unsigned int uCtrl, unsigned int uData, int internal_id);

    void (*stream_callback)(Uint8 *stream, int length,
                            int internal_id); // callback to write stream to
                                              // buffer

    // *** THIS SECTION IS DEFINED WHEN SOUND CHIP IS ADDED
    int type;  // type of sound chip (See enum's)
    Uint32 hz; // speed of sound chip in Hz

    // Should be true if sound quality of chip is better the more often it is
    // updated.
    //  An example is Super Don's sound chip.
    // Should be false if sound doesn't change no matter how fast it is updated.
    //  An example is VLDP which has constant pre-defined audio.
    // FIXME : in the future this should be changed to define how frequent of
    // updates are
    //  needed, because the less frequent of updates, the better.
    bool bNeedsConstantUpdates;
};

// adds a new soundchip and returns the ID
unsigned int add_chip(struct chip *); // add a new cpu

// deletes a soundchip that has previously been added
bool delete_chip(unsigned int id);

void init_chip(); // inits all the sound chips

// Mixing callback
// USED WHEN : all audio is muted
void mixMute(Uint8 *stream, int length);

// Mixing callback
// USED WHEN: there is only 1 sound chip, then there is no need to do any mixing
// (fastest)
void mixNone(Uint8 *stream, int length);

// Mixing callback
// USED WHEN: there are more than 1 sound chip, but all volumes are maximum
// (pretty fast)
void mixWithMaxVolume(Uint8 *stream, int length);

// Mixing callback
// USED WHEN: there are more than 1 sound chip, and volumes are variable
// (this is the slowest callback, only use it if you must)
void mixWithMults(Uint8 *stream, int length);

void SDLCALL StreamAudio(void *, SDL_AudioStream *, int, int);
void writedata(Uint8, Uint8);

// for game driver to send commands to sound chip
void write_ctrl_data(unsigned int uCtrl, unsigned int uData, Uint8 id);

// Used to set the volume of an audio stream. Valid volume values are 0 to
// MAX_VOLUME.
// 'id' is the id returned by add_soundchip()
// 'channel' is which audio channel to the set the volume for (0 = left, 1 =
// right I think)
// WARNING : setting the volume to anything lower than MAX_VOLUME may
// incur a (small?)
//  performance penalty and should be avoided if there is little benefit to
//  adjusting
//  the volume.
// If there is an error, the logfile will be notified and the quitflag may be
// set :)
void set_chip_volume(Uint8 id, unsigned int uChannel, unsigned int uVolume);

// helper function for the other set_soundchip_volume
void set_chip_volume(struct chip *cur, unsigned int uChannel, unsigned int uVolume);

// so the user can override the default VLDP volume
void set_chip_vldp_volume(unsigned int uVolume);
unsigned int get_chip_vldp_volume();

// so the user can override the default volume of all soundchips besides VLDP
void set_chip_nonvldp_volume(unsigned int uVolume);
unsigned int get_chip_nonvldp_volume();

// Recalculates uVolume based on values of drivervolume and basevolume
// Also calculates which rshift and callback to use
void update_chip_volumes();

void shutdown_chip();
void update_buffer(); // update the sound buffers with 1 ms worth of data
void set_buf_size(Uint16 newbufsize);
bool init();
void shutdown();
bool play(Uint32 whichone);
bool play_saveme();
int load_waves();
void free_waves();
int get_initialized();
void set_mute(bool bMuted); // added by JFA for -startsilent
void set_enabled_status(bool value);
bool is_enabled();
SDL_AudioSpec *getSpecDesired();

// (re)calculates the right-shift value to be used to mix sounds (for fast
// division)
void sound_recalc_rshift();
}

#endif
