Internal core resampling not necessary - 44Khz should disable

resampler already anyways, so no use having the dead code around
This commit is contained in:
TwinAphex51224 2012-09-22 19:37:26 +02:00
parent 106326e464
commit c9d2d91fee
4 changed files with 2410 additions and 3 deletions

View File

@ -51,7 +51,7 @@ PSX_SOURCES := $(PSX_DIR)/psx.cpp \
$(PSX_DIR)/gte.cpp \
$(PSX_DIR)/dis.cpp \
$(PSX_DIR)/cdc.cpp \
$(PSX_DIR)/spu.cpp \
$(MEDNAFEN_LIBRETRO_DIR)/psx/spu.cpp \
$(PSX_DIR)/gpu.cpp \
$(PSX_DIR)/mdec.cpp \
$(PSX_DIR)/input/gamepad.cpp \
@ -69,7 +69,7 @@ MEDNAFEN_SOURCES := $(MEDNAFEN_DIR)/cdrom/cdromif.cpp \
$(MEDNAFEN_DIR)/netplay.cpp \
$(MEDNAFEN_DIR)/general.cpp \
$(MEDNAFEN_DIR)/player.cpp \
$(MEDNAFEN_DIR)/cdplay.cpp \
$(MEDNAFEN_LIBRETRO_DIR)/cdplay.cpp \
$(MEDNAFEN_DIR)/FileWrapper.cpp \
$(MEDNAFEN_DIR)/state.cpp \
$(MEDNAFEN_DIR)/tests.cpp \
@ -141,7 +141,7 @@ endif
LDFLAGS += $(fpic) -lz $(SHARED)
FLAGS += -msse -msse2 -Wall $(fpic) -fno-strict-overflow
FLAGS += -I. -Imednafen -Imednafen/include -Imednafen/intl
FLAGS += -I. -Imednafen -Imednafen/include -Imednafen/intl -Imednafen/psx
WARNINGS := -Wall \
-Wno-narrowing \

View File

@ -0,0 +1,503 @@
/* Mednafen - Multi-system Emulator
*
* 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
*/
//#include <mednafen/mednafen.h>
#include "mednafen.h"
#include "cdrom/cdromif.h"
#include "netplay.h"
#include <blip/Blip_Buffer.h>
#include <trio/trio.h>
#include <vector>
#include <math.h>
using namespace CDUtility;
namespace MDFN_IEN_CDPLAY
{
static std::vector<double> sqrt_lut; //[65536];
static std::vector<double> sin_lut; //[65536];
static uint8 *controller_ptr;
static uint8 last_controller;
enum
{
PLAYMODE_PAUSE = -1,
PLAYMODE_STOP = 0,
PLAYMODE_PLAY = 1,
PLAYMODE_SCAN_FORWARD = 2,
PLAYMODE_SCAN_REVERSE = 3,
};
static int PlayMode;
static uint32 PlaySector;
static int16 CDDABuffer[588 * 2];
static uint32 PrevRate;
static std::vector<CDIF *> *cdifs;
static int32 CurrentATLI;
struct AudioTrackInfo
{
inline AudioTrackInfo(unsigned disc_, int32 track_, int32 lba_, int32 final_lba_)
{
disc = disc_;
track = track_;
lba = lba_;
final_lba = final_lba_;
}
unsigned disc;
int32 track;
int32 lba;
int32 final_lba; // Inclusive.
};
static std::vector<AudioTrackInfo> AudioTrackList;
static void InitLUT(void);
static int LoadCD(std::vector<CDIF *> *CDInterfaces)
{
cdifs = CDInterfaces;
AudioTrackList.clear();
for(unsigned disc = 0; disc < cdifs->size(); disc++)
{
TOC toc;
(*cdifs)[disc]->ReadTOC(&toc);
for(int32 track = toc.first_track; track <= toc.last_track; track++)
{
if(!(toc.tracks[track].control & 0x4))
{
AudioTrackList.push_back(AudioTrackInfo(disc, track, toc.tracks[track].lba, toc.tracks[track + 1].lba - 1));
}
}
}
if(!AudioTrackList.size())
{
puts("Audio track doesn't exist");
return(0);
}
CurrentATLI = 0;
PlaySector = AudioTrackList[CurrentATLI].lba;
PlayMode = PLAYMODE_PLAY; //STOP;
InitLUT();
return(1);
}
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
CDUtility::TOC magic_toc;
for(unsigned i = 0; i < CDInterfaces->size(); i++)
{
(*CDInterfaces)[i]->ReadTOC(&magic_toc);
// If any audio track is found, return true.
for(int32 track = magic_toc.first_track; track <= magic_toc.last_track; track++)
if(!(magic_toc.tracks[track].control & 0x4))
return(true);
}
return(false);
}
static void CloseGame(void)
{
sin_lut.resize(0);
sqrt_lut.resize(0);
}
static uint8 SubQBuf[3][0xC];
static void GenSubQFromSubPW(uint8 *SubPWBuf)
{
uint8 sq[0xC];
memset(sq, 0, 0xC);
for(int i = 0; i < 96; i++)
sq[i >> 3] |= ((SubPWBuf[i] & 0x40) >> 6) << (7 - (i & 7));
if(!subq_check_checksum(sq))
puts("SubQ checksum error!");
else
{
uint8 adr = sq[0] & 0xF;
if(adr <= 0x3)
memcpy(SubQBuf[adr], sq, 0xC);
}
}
static const int lobes = 2;
static const int oversample_shift = 7; //1; //7;
static const int oversample = 1 << oversample_shift;
static const int oversample_mo = oversample - 1;
static void InitLUT(void)
{
sqrt_lut.resize(65536);
sin_lut.resize(65536);
for(int i = 0; i < 65536; i++)
sqrt_lut[i] = sqrt((double)i / 65536);
for(int i = 0; i < 65536; i++)
sin_lut[i] = sin((double)i * M_PI * 2 / 65536);
}
static void Emulate(EmulateSpecStruct *espec)
{
uint8 sector_buffer[2352 + 96];
uint8 new_controller = *controller_ptr;
espec->MasterCycles = 588;
//printf("%d %d\n", toc.tracks[100].lba, AudioTrackList[AudioTrackList.size() - 1] + 1);
if(PlaySector > AudioTrackList[CurrentATLI].final_lba)
{
if((CurrentATLI + 1) < AudioTrackList.size())
CurrentATLI++;
else
{
CurrentATLI = 0;
PlayMode = PLAYMODE_STOP;
}
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(PlayMode == PLAYMODE_STOP || PlayMode == PLAYMODE_PAUSE)
{
}
else
{
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadRawSector(sector_buffer, PlaySector);
GenSubQFromSubPW(sector_buffer + 2352);
for(int i = 0; i < 588 * 2; i++)
{
CDDABuffer[i] = MDFN_de16lsb(&sector_buffer[i * sizeof(int16)]);
}
}
if(espec->SoundBuf)
{
}
// for(int i = 0; i < espec->SoundBufSize * 2; i++)
// espec->SoundBuf[i] = (rand() & 0x7FFF) - 0x4000; //(rand() * 192) >> 8
if(!espec->skip)
{
char tmpbuf[256];
const MDFN_PixelFormat &format = espec->surface->format;
uint32 *pixels = espec->surface->pixels;
uint32 text_color = format.MakeColor(0xE0, 0xE0, 0xE0);
uint32 text_shadow_color = format.MakeColor(0x20, 0x20, 0x20);
uint32 cur_sector = PlaySector;
espec->DisplayRect.x = 0;
espec->DisplayRect.y = 0;
espec->DisplayRect.w = 320;
espec->DisplayRect.h = 240;
espec->surface->Fill(0, 0, 0, 0);
{
uint32 color_table[256];
for(int i = 0; i < 170; i++)
{
int m = 255 * i / 170;
color_table[i] = format.MakeColor(m, 0, m);
//printf("%d %d %08x\n", m, i, color_table[i]);
}
for(int i = 0; i < 588; i++)
{
int32 unip_samp;
int32 next_unip_samp;
unip_samp = ((CDDABuffer[i * 2 + 0] + CDDABuffer[i * 2 + 1]) >> 1) + 32768;
next_unip_samp = ((CDDABuffer[(i * 2 + 2) % 1176] + CDDABuffer[(i * 2 + 3) % 1176]) >> 1) + 32768;
for(int osi = 0; osi < oversample; osi++)
{
double sample;
int x;
int y;
double x_raw, y_raw;
double x_raw2, y_raw2;
double x_raw_prime, y_raw_prime;
sample = (double)(unip_samp * (oversample - osi) + next_unip_samp * osi) / (oversample * 65536);
int32 theta_i = (int64)65536 * (i * oversample + osi) / (oversample * 588);
int32 theta_i_alt = (int64)65536 * (i * oversample + osi) / (oversample * 588);
double radius = sin_lut[(lobes * theta_i) & 0xFFFF]; // * sin_lut[(16384 + (theta_i)) & 0xFFFF];
double radius2 = sin_lut[(lobes * (theta_i + 1)) & 0xFFFF]; // * sin_lut[(16384 + ((theta_i + 1))) & 0xFFFF];
x_raw = radius * sin_lut[(16384 + theta_i_alt) & 0xFFFF];
y_raw = radius * sin_lut[theta_i_alt & 0xFFFF];
x_raw2 = radius2 * sin_lut[(16384 + theta_i_alt + 1) & 0xFFFF];
y_raw2 = radius2 * sin_lut[(theta_i_alt + 1) & 0xFFFF];
// Approximation, of course.
x_raw_prime = (x_raw2 - x_raw) / (1 * M_PI * 2 / 65536);
y_raw_prime = (y_raw2 - y_raw) / (1 * M_PI * 2 / 65536);
// printf("%f %f\n", y_raw_prime, sin_lut[(16384 + lobes * theta_i_alt) & 0xFFFF] + sin_lut[(16384 + theta_i_alt) & 0xFFFF]);
if(x_raw_prime || y_raw_prime)
{
x_raw_prime = x_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
y_raw_prime = y_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
}
x_raw += (sample - 0.5) * y_raw_prime / 2;
y_raw += (sample - 0.5) * -x_raw_prime / 2;
x = 160 + 100 * x_raw;
y = 120 + 100 * y_raw;
if((x >= 0 && x < 320) && (y >= 0 && y < 240))
pixels[x + y * espec->surface->pitch32] = format.MakeColor(255, 255, 255); //color_table[(int)(sample * 150)]; //x * x + y * y; //format.MakeColor(sample * 255, 0, sample * 255);
}
}
}
{
TOC toc;
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadTOC(&toc);
trio_snprintf(tmpbuf, 256, "Disc: %d/%d", AudioTrackList[CurrentATLI].disc + 1, cdifs->size());
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Track: %d/%d", AudioTrackList[CurrentATLI].track, toc.last_track);
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Sector: %d/%d", cur_sector, toc.tracks[100].lba - 1);
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
}
pixels += 22 * espec->surface->pitch32;
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)"SubQ", text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
//trio_snprintf(tmpbuf, 256, "Q-Mode: %01x", SubQBuf[1][0] & 0xF);
//DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
//pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Track: %d", BCD_to_U8(SubQBuf[1][1]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Index: %d", BCD_to_U8(SubQBuf[1][2]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Relative: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][3]), BCD_to_U8(SubQBuf[1][4]), BCD_to_U8(SubQBuf[1][5]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Absolute: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][7]), BCD_to_U8(SubQBuf[1][8]), BCD_to_U8(SubQBuf[1][9]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
}
if(PlayMode != PLAYMODE_STOP && PlayMode != PLAYMODE_PAUSE)
PlaySector++;
if(!(last_controller & 0x1) && (new_controller & 1))
{
PlayMode = (PlayMode == PLAYMODE_PLAY) ? PLAYMODE_PAUSE : PLAYMODE_PLAY;
}
if(!(last_controller & 0x2) && (new_controller & 2)) // Stop
{
PlayMode = PLAYMODE_STOP;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x4) && (new_controller & 4))
{
if(CurrentATLI < (AudioTrackList.size() - 1))
CurrentATLI++;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x8) && (new_controller & 8))
{
if(CurrentATLI)
CurrentATLI--;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x10) && (new_controller & 0x10))
{
CurrentATLI = std::min<int>(CurrentATLI + 10, AudioTrackList.size() - 1);
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x20) && (new_controller & 0x20))
{
CurrentATLI = std::max<int>(CurrentATLI - 10, 0);
PlaySector = AudioTrackList[CurrentATLI].lba;
}
last_controller = new_controller;
}
static const FileExtensionSpecStruct KnownExtensions[] =
{
{ NULL, NULL }
};
static void SetInput(int port, const char *type, void *ptr)
{
controller_ptr = (uint8 *)ptr;
}
static void DoSimpleCommand(int cmd)
{
switch(cmd)
{
case MDFNNPCMD_POWER:
case MDFNNPCMD_RESET: break;
}
}
static MDFNSetting CDPlaySettings[] =
{
{ NULL }
};
static const InputDeviceInputInfoStruct IDII[] =
{
{ "play_pause", "Play/Pause", 0, IDIT_BUTTON, NULL },
{ "stop", "Stop", 1, IDIT_BUTTON, NULL },
{ "next_track", "Next Track", 2, IDIT_BUTTON, NULL },
{ "previous_track", "Previous Track", 3, IDIT_BUTTON, NULL },
{ "next_track_10", "Next Track 10", 4, IDIT_BUTTON, NULL },
{ "previous_track_10", "Previous Track 10", 5, IDIT_BUTTON, NULL },
{ "scan_forward", "Scan Forward", 6, IDIT_BUTTON, NULL },
{ "scan_reverse", "Scan Reverse", 7, IDIT_BUTTON, NULL },
//{ "reverse_seek", "Reverse Seek", 1, IDIT_BUTTON, NULL },
//{ "forward_seek", "Forward Seek", 2, IDIT_BUTTON, NULL },
//{ "fast_reverse_seek", "Fast Reverse Seek", 3, IDIT_BUTTON, NULL },
//{ "fast_forward_seek", "Fast Forward Seek", 4, IDIT_BUTTON, NULL },
};
static InputDeviceInfoStruct InputDeviceInfo[] =
{
{
"controller",
"Controller",
NULL,
sizeof(IDII) / sizeof(InputDeviceInputInfoStruct),
IDII,
}
};
static const InputPortInfoStruct PortInfo[] =
{
{ 0, "builtin", "Built-In", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo }
};
static InputInfoStruct InputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
}
using namespace MDFN_IEN_CDPLAY;
MDFNGI EmulatedCDPlay =
{
"cdplay",
"Mednafen Test CD-DA Player",
KnownExtensions,
MODPRIO_INTERNAL_EXTRA_LOW,
NULL, // Debug info
&InputInfo, //
NULL,
NULL,
LoadCD,
TestMagicCD,
CloseGame,
NULL,
NULL, // Layer names, null-delimited
NULL,
NULL,
NULL,
NULL,
NULL,
false,
NULL, //StateAction,
Emulate,
SetInput,
DoSimpleCommand,
CDPlaySettings,
MDFN_MASTERCLOCK_FIXED(44100),
75 * 65536 * 256,
false, // Multires possible?
320, // lcm_width
240, // lcm_height
NULL, // Dummy
320, // Nominal width
240, // Nominal height
512, // Framebuffer width
256, // Framebuffer height
2, // Number of output sound channels
};

File diff suppressed because it is too large Load Diff

338
mednafen-libretro/psx/spu.h Normal file
View File

@ -0,0 +1,338 @@
#ifndef __MDFN_PSX_SPU_H
#define __MDFN_PSX_SPU_H
namespace MDFN_IEN_PSX
{
enum
{
ADSR_ATTACK = 0,
ADSR_DECAY = 1,
ADSR_SUSTAIN = 2,
ADSR_RELEASE = 3
};
struct SPU_ADSR
{
uint16 EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers
// may not treat consistently.
uint32 Divider;
uint32 Phase;
bool AttackExp;
bool SustainExp;
bool SustainDec;
bool ReleaseExp;
int32 AttackRate; // Ar
int32 DecayRate; // Dr * 4
int32 SustainRate; // Sr
int32 ReleaseRate; // Rr * 4
int32 SustainLevel; // (Sl + 1) << 11
};
class PS_SPU;
class SPU_Sweep
{
friend class PS_SPU; // For save states - FIXME(remove in future?)
public:
SPU_Sweep() { }
~SPU_Sweep() { }
void Power(void);
void WriteControl(uint16 value);
int16 ReadVolume(void);
void WriteVolume(int16 value);
void Clock(void);
private:
uint16 Control;
int16 Current;
uint32 Divider;
};
struct SPU_Voice
{
int32 DecodeBuffer[32 + 4]; // + 4 so we don't have to do & 0x1F in our MAC
int32 DecodeWritePos;
uint8 DecodeFlags;
SPU_Sweep Sweep[2];
uint16 Pitch;
uint32 CurPhase;
int32 CurPhase_SD; // Offseted compared to CurPhase, used for triggering sample decode.
uint32 StartAddr;
uint32 CurAddr;
uint32 ADSRControl;
uint32 LoopAddr;
int32 PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767
SPU_ADSR ADSR;
};
class PS_SPU
{
public:
PS_SPU();
~PS_SPU();
int StateAction(StateMem *sm, int load, int data_only);
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V);
uint16 Read(pscpu_timestamp_t timestamp, uint32 A);
void WriteDMA(uint32 V);
uint32 ReadDMA(void);
void StartFrame(double rate, uint32 quality);
int32 EndFrame(int16 *SoundBuf);
int32 UpdateFromCDC(int32 clocks);
//pscpu_timestamp_t Update(pscpu_timestamp_t timestamp);
static void DecodeADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight);
private:
void CheckIRQAddr(uint32 addr);
void WriteSPURAM(uint32 addr, uint16 value);
uint16 ReadSPURAM(uint32 addr);
void DecodeSamples(SPU_Voice *voice);
void CacheEnvelope(SPU_Voice *voice);
void ResetEnvelope(SPU_Voice *voice);
void ReleaseEnvelope(SPU_Voice *voice);
void RunEnvelope(SPU_Voice *voice);
void RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r);
bool GetCDAudio(int32 &l, int32 &r);
SPU_Voice Voices[24];
uint32 NoiseCounter;
uint16 LFSR;
uint32 FM_Mode;
uint32 Noise_Mode;
uint32 Reverb_Mode;
int32 ReverbWA;
SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume!
int32 ReverbVol[2];
int32 CDVol[2];
int32 ExternVol[2];
uint32 IRQAddr;
uint32 RWAddr;
uint16 SPUControl;
uint32 VoiceOn;
uint32 VoiceOff;
uint32 BlockEnd;
uint32 CWA;
int32 CDXA_ResampBuffer[2][4];
int32 CDXA_CurPhase;
union
{
uint16 Regs[0x100];
struct
{
uint16 VoiceRegs[0xC0];
union
{
uint16 GlobalRegs[0x20];
struct
{
uint16 _Global0[0x17];
uint16 SPUStatus;
uint16 _Global1[0x08];
};
};
union
{
int16 ReverbRegs[0x20];
struct
{
int16 FB_SRC_A;
int16 FB_SRC_B;
int16 IIR_ALPHA;
int16 ACC_COEF_A;
int16 ACC_COEF_B;
int16 ACC_COEF_C;
int16 ACC_COEF_D;
int16 IIR_COEF;
int16 FB_ALPHA;
int16 FB_X;
int16 IIR_DEST_A0;
int16 IIR_DEST_A1;
int16 ACC_SRC_A0;
int16 ACC_SRC_A1;
int16 ACC_SRC_B0;
int16 ACC_SRC_B1;
int16 IIR_SRC_A0;
int16 IIR_SRC_A1;
int16 IIR_DEST_B0;
int16 IIR_DEST_B1;
int16 ACC_SRC_C0;
int16 ACC_SRC_C1;
int16 ACC_SRC_D0;
int16 ACC_SRC_D1;
int16 IIR_SRC_B1;
int16 IIR_SRC_B0;
int16 MIX_DEST_A0;
int16 MIX_DEST_A1;
int16 MIX_DEST_B0;
int16 MIX_DEST_B1;
int16 IN_COEF_L;
int16 IN_COEF_R;
};
};
};
};
uint16 AuxRegs[0x10];
int16 RDSB[2][128]; // [40]
int32 RDSB_WP;
int16 RUSB[2][128];
int32 RUSB_WP;
int32 ReverbCur;
int32 Get_Reverb_Offset(int32 offset);
int32 RD_RVB(int16 raw_offs);
void WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs = 0);
bool IRQAsserted;
//pscpu_timestamp_t lastts;
int32 clock_divider;
uint16 SPURAM[524288 / sizeof(uint16)];
int last_rate;
uint32 last_quality;
// Buffers 44.1KHz samples, should have enough for one video frame(~735 frames NTSC, ~882 PAL) plus jitter plus enough for the resampler leftovers.
// We'll just go with 4096 because powers of 2 are AWESOME and such.
uint32 IntermediateBufferPos;
int16 IntermediateBuffer[4096][2];
public:
enum
{
GSREG_SPUCONTROL = 0,
GSREG_FM_ON,
GSREG_NOISE_ON,
GSREG_REVERB_ON,
GSREG_CDVOL_L,
GSREG_CDVOL_R,
GSREG_DRYVOL_CTRL_L,
GSREG_DRYVOL_CTRL_R,
GSREG_DRYVOL_L,
GSREG_DRYVOL_R,
GSREG_WETVOL_L,
GSREG_WETVOL_R,
GSREG_RWADDR,
GSREG_IRQADDR,
GSREG_REVERBWA,
GSREG_VOICEON,
GSREG_VOICEOFF,
GSREG_BLOCKEND,
// Note: the order of these should match the reverb reg array
GSREG_FB_SRC_A,
GSREG_FB_SRC_B,
GSREG_IIR_ALPHA,
GSREG_ACC_COEF_A,
GSREG_ACC_COEF_B,
GSREG_ACC_COEF_C,
GSREG_ACC_COEF_D,
GSREG_IIR_COEF,
GSREG_FB_ALPHA,
GSREG_FB_X,
GSREG_IIR_DEST_A0,
GSREG_IIR_DEST_A1,
GSREG_ACC_SRC_A0,
GSREG_ACC_SRC_A1,
GSREG_ACC_SRC_B0,
GSREG_ACC_SRC_B1,
GSREG_IIR_SRC_A0,
GSREG_IIR_SRC_A1,
GSREG_IIR_DEST_B0,
GSREG_IIR_DEST_B1,
GSREG_ACC_SRC_C0,
GSREG_ACC_SRC_C1,
GSREG_ACC_SRC_D0,
GSREG_ACC_SRC_D1,
GSREG_IIR_SRC_B1,
GSREG_IIR_SRC_B0,
GSREG_MIX_DEST_A0,
GSREG_MIX_DEST_A1,
GSREG_MIX_DEST_B0,
GSREG_MIX_DEST_B1,
GSREG_IN_COEF_L,
GSREG_IN_COEF_R,
// Multiply v * 256 for each extra voice
GSREG_V0_VOL_CTRL_L = 0x8000,
GSREG_V0_VOL_CTRL_R,
GSREG_V0_VOL_L,
GSREG_V0_VOL_R,
GSREG_V0_PITCH,
GSREG_V0_STARTADDR,
GSREG_V0_ADSR_CTRL,
GSREG_V0_ADSR_LEVEL,
GSREG_V0_LOOP_ADDR,
GSREG_V0_READ_ADDR
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
uint16 PeekSPURAM(uint32 address);
void PokeSPURAM(uint32 address, uint16 value);
};
}
#endif