mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2025-02-19 23:00:42 +00:00
Internal core resampling not necessary - 44Khz should disable
resampler already anyways, so no use having the dead code around
This commit is contained in:
parent
106326e464
commit
c9d2d91fee
6
Makefile
6
Makefile
@ -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 \
|
||||
|
503
mednafen-libretro/cdplay.cpp
Normal file
503
mednafen-libretro/cdplay.cpp
Normal 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(§or_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
|
||||
};
|
||||
|
1566
mednafen-libretro/psx/spu.cpp
Normal file
1566
mednafen-libretro/psx/spu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
338
mednafen-libretro/psx/spu.h
Normal file
338
mednafen-libretro/psx/spu.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user