/*
Copyright 2006 Theo Berkau
Copyright (C) 2006-2015 DeSmuME team
This file 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 file 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 the this software. If not, see .
*/
#ifndef SPU_H
#define SPU_H
#include
#include
#include
#include
#include
#include "types.h"
#include "matrix.h"
#include "metaspu/metaspu.h"
class EMUFILE;
#define SNDCORE_DEFAULT -1
#define SNDCORE_DUMMY 0
#define CHANSTAT_STOPPED 0
#define CHANSTAT_PLAY 1
//who made these static? theyre used in multiple places.
FORCEINLINE u32 sputrunc(float f) { return u32floor(f); }
FORCEINLINE u32 sputrunc(double d) { return u32floor(d); }
FORCEINLINE s32 spumuldiv7(s32 val, u8 multiplier) {
assert(multiplier <= 127);
return (multiplier == 127) ? val : ((val * multiplier) >> 7);
}
enum SPUInterpolationMode
{
SPUInterpolation_None = 0,
SPUInterpolation_Linear = 1,
SPUInterpolation_Cosine = 2,
SPUInterpolation_Sharp = 3
};
struct SoundInterface_struct
{
int id;
const char *Name;
int (*Init)(int buffersize);
void (*DeInit)();
void (*UpdateAudio)(s16 *buffer, u32 num_samples);
u32 (*GetAudioSpace)();
void (*MuteAudio)();
void (*UnMuteAudio)();
void (*SetVolume)(int volume);
void (*ClearBuffer)();
void (*FetchSamples)(s16 *sampleBuffer, size_t sampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
size_t (*PostProcessSamples)(s16 *postProcessBuffer, size_t requestedSampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
};
extern SoundInterface_struct SNDDummy;
extern SoundInterface_struct SNDFile;
extern int SPU_currentCoreNum;
struct channel_struct
{
channel_struct() : num(0),
vol(0),
volumeDiv(0),
hold(0),
pan(0),
waveduty(0),
repeat(0),
format(0),
keyon(0),
status(0),
addr(0),
timer(0),
loopstart(0),
length(0),
totlength(0),
double_totlength_shifted(0.0),
sampcnt(0.0),
sampinc(0.0),
lastsampcnt(0),
pcm16b(0),
pcm16b_last(0),
loop_pcm16b(0),
index(0),
loop_index(0),
x(0),
psgnoise_last(0)
{}
u32 num;
u8 vol;
u8 volumeDiv;
u8 hold;
u8 pan;
u8 waveduty;
u8 repeat;
u8 format;
u8 keyon;
u8 status;
u32 addr;
u16 timer;
u16 loopstart;
u32 length;
u32 totlength;
double double_totlength_shifted;
double sampcnt;
double sampinc;
// ADPCM specific
u32 lastsampcnt;
s16 pcm16b, pcm16b_last;
s16 loop_pcm16b;
s32 index;
int loop_index;
u16 x;
s16 psgnoise_last;
};
class SPUFifo
{
public:
SPUFifo();
void enqueue(s16 val);
s16 dequeue();
s16 buffer[16];
s32 head,tail,size;
void reset();
};
class SPU_struct
{
public:
SPU_struct(int buffersize);
u32 bufpos;
u32 buflength;
s32 *sndbuf;
s32 lastdata; //the last sample that a channel generated
s16 *outbuf;
u32 bufsize;
channel_struct channels[16];
//registers
struct REGS {
REGS()
: mastervol(0)
, ctl_left(0)
, ctl_right(0)
, ctl_ch1bypass(0)
, ctl_ch3bypass(0)
, masteren(0)
, soundbias(0)
{}
u8 mastervol;
u8 ctl_left, ctl_right;
u8 ctl_ch1bypass, ctl_ch3bypass;
u8 masteren;
u16 soundbias;
enum LeftOutputMode
{
LOM_LEFT_MIXER=0, LOM_CH1=1, LOM_CH3=2, LOM_CH1_PLUS_CH3=3
};
enum RightOutputMode
{
ROM_RIGHT_MIXER=0, ROM_CH1=1, ROM_CH3=2, ROM_CH1_PLUS_CH3=3
};
struct CAP {
CAP()
: add(0), source(0), oneshot(0), bits8(0), active(0), dad(0), len(0)
{}
u8 add, source, oneshot, bits8, active;
u32 dad;
u16 len;
struct Runtime {
Runtime()
: running(0), curdad(0), maxdad(0)
{}
u8 running;
u32 curdad;
u32 maxdad;
double sampcnt;
SPUFifo fifo;
} runtime;
} cap[2];
} regs;
void reset();
~SPU_struct();
void KeyOff(int channel);
void KeyOn(int channel);
void KeyProbe(int channel);
void ProbeCapture(int which);
void WriteByte(u32 addr, u8 val);
void WriteWord(u32 addr, u16 val);
void WriteLong(u32 addr, u32 val);
u8 ReadByte(u32 addr);
u16 ReadWord(u32 addr);
u32 ReadLong(u32 addr);
bool isSPU(u32 addr) { return ((addr >= 0x04000400) && (addr < 0x04000520)); }
//kills all channels but leaves SPU otherwise running normally
void ShutUp();
};
extern SPU_struct *SPU_core;
extern int spu_core_samples;
int SPU_ChangeSoundCore(int coreid, int buffersize);
SoundInterface_struct *SPU_SoundCore();
void SPU_ReInit(bool fakeBoot = false);
int SPU_Init(int coreid, int buffersize);
void SPU_Pause(int pause);
void SPU_SetVolume(int volume);
void SPU_SetSynchMode(int mode, int method);
void SPU_ClearOutputBuffer(void);
void SPU_Reset(void);
void SPU_DeInit(void);
void SPU_KeyOn(int channel);
static FORCEINLINE void SPU_WriteByte(u32 addr, u8 val)
{
addr &= 0xFFF;
SPU_core->WriteByte(addr,val);
}
static FORCEINLINE void SPU_WriteWord(u32 addr, u16 val)
{
addr &= 0xFFF;
SPU_core->WriteWord(addr,val);
}
static FORCEINLINE void SPU_WriteLong(u32 addr, u32 val)
{
addr &= 0xFFF;
SPU_core->WriteLong(addr,val);
}
static FORCEINLINE u8 SPU_ReadByte(u32 addr) { return SPU_core->ReadByte(addr & 0x0FFF); }
static FORCEINLINE u16 SPU_ReadWord(u32 addr) { return SPU_core->ReadWord(addr & 0x0FFF); }
static FORCEINLINE u32 SPU_ReadLong(u32 addr) { return SPU_core->ReadLong(addr & 0x0FFF); }
void SPU_Emulate_core(void);
void SPU_Emulate_user(bool mix = true);
void SPU_DefaultFetchSamples(s16 *sampleBuffer, size_t sampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
size_t SPU_DefaultPostProcessSamples(s16 *postProcessBuffer, size_t requestedSampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
extern double DESMUME_SAMPLE_RATE;
void SetDesmumeSampleRate(double rate);
#endif