mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64e17fce3f | ||
|
|
518728ca36 | ||
|
|
d1a7430f80 | ||
|
|
973c522756 | ||
|
|
5536342f9d | ||
|
|
d9ddab1a33 | ||
|
|
c915aac1fa | ||
|
|
a3c2a4db5f | ||
|
|
aebebf5115 | ||
|
|
9a50218400 | ||
|
|
fd5a652270 | ||
|
|
c647a30aa9 | ||
|
|
40d5c78573 | ||
|
|
fe2a9fc2cd | ||
|
|
83f9add68b | ||
|
|
ffe8d16df4 | ||
|
|
31b5672870 | ||
|
|
777fc444ae | ||
|
|
cd5c961dc4 | ||
|
|
c2ea8c4eab | ||
|
|
d6507a945b | ||
|
|
f1abee5d0b |
@@ -1208,6 +1208,8 @@ SCAJ-20027:
|
||||
SCAJ-20028:
|
||||
name: "Tales of Destiny 2"
|
||||
region: "NTSC-Unk"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SCAJ-20029:
|
||||
name: "R-Type Final"
|
||||
region: "NTSC-Unk"
|
||||
@@ -1848,6 +1850,8 @@ SCAJ-20146:
|
||||
name: "Wang Da Yu Ju Xiang"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -2142,6 +2146,8 @@ SCAJ-20195:
|
||||
SCAJ-20196:
|
||||
name: "Wang Da Yu Ju Xiang [PlayStation 2 the Best]"
|
||||
region: "NTSC-C"
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -3964,6 +3970,8 @@ SCED-53947:
|
||||
SCED-53962:
|
||||
name: "Shadow of the Colossus [Demo]"
|
||||
region: "PAL-M5"
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -5576,6 +5584,8 @@ SCES-53326:
|
||||
name: "Shadow of the Colossus"
|
||||
region: "PAL-E"
|
||||
compat: 5
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -6629,6 +6639,8 @@ SCKA-20008:
|
||||
name: "Tales of Destiny 2"
|
||||
region: "NTSC-K"
|
||||
compat: 5
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SCKA-20009:
|
||||
name: "R-Type Final"
|
||||
region: "NTSC-K"
|
||||
@@ -6949,6 +6961,8 @@ SCKA-20053:
|
||||
SCKA-20054:
|
||||
name: "Tales of Destiny 2 [PlayStation 2 Big Hit Series]"
|
||||
region: "NTSC-K"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SCKA-20055:
|
||||
name: "Mystic Nights"
|
||||
region: "NTSC-K"
|
||||
@@ -6989,6 +7003,8 @@ SCKA-20061:
|
||||
name: "Wanda to Kyozou"
|
||||
region: "NTSC-K"
|
||||
compat: 5
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -8550,6 +8566,8 @@ SCPS-15097:
|
||||
name-en: "Wanda to Kyozou"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -9297,6 +9315,8 @@ SCPS-19320:
|
||||
name-sort: "わんだときょぞう PlayStation 2 the Best"
|
||||
name-en: "Wanda to Kyozou [PlayStation 2 the Best]"
|
||||
region: "NTSC-J"
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -9453,6 +9473,8 @@ SCPS-19333:
|
||||
SCPS-19335:
|
||||
name: "Wanda to Kyozou [PlayStation 2 the Best Reprint]"
|
||||
region: "NTSC-J"
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -9760,6 +9782,8 @@ SCPS-55049:
|
||||
SCPS-55050:
|
||||
name: "Tales of Destiny 2"
|
||||
region: "NTSC-J"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SCPS-55901:
|
||||
name: "Xenosaga Episode I - Der Wille zur Macht"
|
||||
region: "NTSC-J"
|
||||
@@ -11344,6 +11368,8 @@ SCUS-97472:
|
||||
name: "Shadow of the Colossus"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -11561,6 +11587,8 @@ SCUS-97504:
|
||||
SCUS-97505:
|
||||
name: "Shadow of the Colossus [Demo]"
|
||||
region: "NTSC-U"
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Prevents Wander from moving when charging the floor.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes water color.
|
||||
halfPixelOffset: 1 # Fixes misalignments and borders on side.
|
||||
@@ -18588,10 +18616,10 @@ SLES-52291:
|
||||
name: "Countryside Bears"
|
||||
region: "PAL-M3"
|
||||
SLES-52292:
|
||||
name: "Disney's Mighty Mulan"
|
||||
name: "Mighty Mulan"
|
||||
region: "PAL-M3"
|
||||
SLES-52293:
|
||||
name: "Disney's Son of the Lion King"
|
||||
name: "Son of the Lion King"
|
||||
region: "PAL-M3"
|
||||
SLES-52294:
|
||||
name: "The Toys Room"
|
||||
@@ -52834,6 +52862,8 @@ SLPS-25172:
|
||||
name-sort: "ているず おぶ ですてぃにー2"
|
||||
name-en: "Tales of Destiny 2"
|
||||
region: "NTSC-J"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SLPS-25173:
|
||||
name: "Omoide ni Kawaru Kimi - Memories Off"
|
||||
region: "NTSC-J"
|
||||
@@ -57466,6 +57496,8 @@ SLPS-72502:
|
||||
name-sort: "ているず おぶ でぃすてぃにー2 MEGA HITS!"
|
||||
name-en: "Tales of Destiny 2 [Mega Hits]"
|
||||
region: "NTSC-J"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SLPS-73001:
|
||||
name: "Pilot ni Narou! 2"
|
||||
region: "NTSC-J"
|
||||
@@ -57715,6 +57747,8 @@ SLPS-73219:
|
||||
name-sort: "ているず おぶ でぃすてぃにー2 PlayStation 2 the Best"
|
||||
name-en: "Tales of Destiny 2 [PlayStation 2 the Best]"
|
||||
region: "NTSC-J"
|
||||
speedHacks:
|
||||
mvuFlag: 0 # Fixes graphical corruptions.
|
||||
SLPS-73220:
|
||||
name: "ウルトラマン PlayStation 2 the Best"
|
||||
name-sort: "うるとらまん PlayStation 2 the Best"
|
||||
|
||||
@@ -862,9 +862,15 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
// PABE
|
||||
if (PS_PABE)
|
||||
{
|
||||
// As_rgba needed for accumulation blend to manipulate Cd.
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
{
|
||||
As_rgba.rgb = (float3)0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
As_rgba.rgb = (float3)1.0f;
|
||||
}
|
||||
|
||||
float4 RT = SW_BLEND_NEEDS_RT ? RtTexture.Load(int3(pos_xy, 0)) : (float4)0.0f;
|
||||
|
||||
@@ -783,9 +783,15 @@ float As = As_rgba.a;
|
||||
|
||||
// PABE
|
||||
#if PS_PABE
|
||||
// As_rgba needed for accumulation blend to manipulate Cd.
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
{
|
||||
As_rgba.rgb = vec3(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
As_rgba.rgb = vec3(1.0f);
|
||||
#endif
|
||||
|
||||
#if SW_BLEND_NEEDS_RT
|
||||
|
||||
@@ -1050,9 +1050,15 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
|
||||
// PABE
|
||||
#if PS_PABE
|
||||
// As_rgba needed for accumulation blend to manipulate Cd
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
{
|
||||
As_rgba.rgb = vec3(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
As_rgba.rgb = vec3(1.0f);
|
||||
#endif
|
||||
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED
|
||||
|
||||
@@ -1196,7 +1196,7 @@ size_t FileSystem::ReadFileWithProgress(std::FILE* fp, void* dst, size_t length,
|
||||
break;
|
||||
|
||||
const size_t read_size = std::min(length - done, chunk_size);
|
||||
if (std::fread(static_cast<u8*>(dst)+ done, read_size, 1, fp) != 1)
|
||||
if (std::fread(static_cast<u8*>(dst) + done, read_size, 1, fp) != 1)
|
||||
{
|
||||
Error::SetErrno(error, "fread() failed: ", errno);
|
||||
break;
|
||||
@@ -1460,7 +1460,24 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
|
||||
return false;
|
||||
|
||||
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)
|
||||
{
|
||||
std::sort(results->begin(), results->end(), [](const FILESYSTEM_FIND_DATA& lhs, const FILESYSTEM_FIND_DATA& rhs) {
|
||||
// directories first
|
||||
if ((lhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) !=
|
||||
(rhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
return ((lhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
}
|
||||
|
||||
return (StringUtil::Strcasecmp(lhs.FileName.c_str(), rhs.FileName.c_str()) < 0);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void TranslateStat64(struct stat* st, const struct _stat64& st64)
|
||||
@@ -1945,7 +1962,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
|
||||
outData.Attributes = 0;
|
||||
|
||||
struct stat sDir;
|
||||
if (stat(full_path.c_str(), &sDir) < 0)
|
||||
if (lstat(full_path.c_str(), &sDir) < 0)
|
||||
continue;
|
||||
|
||||
if (S_ISDIR(sDir.st_mode))
|
||||
@@ -2042,7 +2059,24 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
|
||||
}
|
||||
|
||||
// enter the recursive function
|
||||
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
|
||||
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
|
||||
return false;
|
||||
|
||||
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)
|
||||
{
|
||||
std::sort(results->begin(), results->end(), [](const FILESYSTEM_FIND_DATA& lhs, const FILESYSTEM_FIND_DATA& rhs) {
|
||||
// directories first
|
||||
if ((lhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) !=
|
||||
(rhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
return ((lhs.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
}
|
||||
|
||||
return (StringUtil::Strcasecmp(lhs.FileName.c_str(), rhs.FileName.c_str()) < 0);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileSystem::StatFile(const char* path, struct stat* st)
|
||||
@@ -2067,7 +2101,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* sd)
|
||||
|
||||
// stat file
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) < 0)
|
||||
if (lstat(path, &sysStatData) < 0)
|
||||
return false;
|
||||
|
||||
// parse attributes
|
||||
@@ -2123,7 +2157,7 @@ bool FileSystem::FileExists(const char* path)
|
||||
|
||||
// stat file
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) < 0)
|
||||
if (lstat(path, &sysStatData) < 0)
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(sysStatData.st_mode))
|
||||
@@ -2140,7 +2174,7 @@ bool FileSystem::DirectoryExists(const char* path)
|
||||
|
||||
// stat file
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) < 0)
|
||||
if (lstat(path, &sysStatData) < 0)
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(sysStatData.st_mode))
|
||||
@@ -2190,7 +2224,7 @@ bool FileSystem::CreateDirectoryPath(const char* path, bool recursive, Error* er
|
||||
{
|
||||
// check the attributes
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) == 0 && S_ISDIR(sysStatData.st_mode))
|
||||
if (lstat(path, &sysStatData) == 0 && S_ISDIR(sysStatData.st_mode))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2260,7 +2294,7 @@ bool FileSystem::DeleteFilePath(const char* path, Error* error)
|
||||
}
|
||||
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) != 0 || S_ISDIR(sysStatData.st_mode))
|
||||
if (lstat(path, &sysStatData) != 0 || S_ISDIR(sysStatData.st_mode))
|
||||
{
|
||||
Error::SetStringView(error, "File does not exist.");
|
||||
return false;
|
||||
@@ -2300,7 +2334,7 @@ bool FileSystem::DeleteDirectory(const char* path)
|
||||
return false;
|
||||
|
||||
struct stat sysStatData;
|
||||
if (stat(path, &sysStatData) != 0 || !S_ISDIR(sysStatData.st_mode))
|
||||
if (lstat(path, &sysStatData) != 0 || !S_ISDIR(sysStatData.st_mode))
|
||||
return false;
|
||||
|
||||
return (rmdir(path) == 0);
|
||||
|
||||
@@ -39,6 +39,7 @@ enum FILESYSTEM_FIND_FLAGS
|
||||
FILESYSTEM_FIND_FOLDERS = (1 << 3),
|
||||
FILESYSTEM_FIND_FILES = (1 << 4),
|
||||
FILESYSTEM_FIND_KEEP_ARRAY = (1 << 5),
|
||||
FILESYSTEM_FIND_SORT_BY_NAME = (1 << 6),
|
||||
};
|
||||
|
||||
struct FILESYSTEM_STAT_DATA
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "ScopedGuard.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include <common/FastJmp.h>
|
||||
#include <jpeglib.h>
|
||||
#include <png.h>
|
||||
#include <webp/decode.h>
|
||||
@@ -383,39 +384,40 @@ namespace
|
||||
struct JPEGErrorHandler
|
||||
{
|
||||
jpeg_error_mgr err;
|
||||
jmp_buf jbuf;
|
||||
fastjmp_buf jbuf;
|
||||
|
||||
JPEGErrorHandler()
|
||||
{
|
||||
jpeg_std_error(&err);
|
||||
err.error_exit = &ErrorExit;
|
||||
}
|
||||
|
||||
static void ErrorExit(j_common_ptr cinfo)
|
||||
{
|
||||
JPEGErrorHandler* eh = (JPEGErrorHandler*)cinfo->err;
|
||||
char msg[JMSG_LENGTH_MAX];
|
||||
eh->err.format_message(cinfo, msg);
|
||||
Console.ErrorFmt("libjpeg fatal error: {}", msg);
|
||||
fastjmp_jmp(&eh->jbuf, 1);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static bool HandleJPEGError(JPEGErrorHandler* eh)
|
||||
{
|
||||
jpeg_std_error(&eh->err);
|
||||
|
||||
eh->err.error_exit = [](j_common_ptr cinfo) {
|
||||
JPEGErrorHandler* eh = (JPEGErrorHandler*)cinfo->err;
|
||||
char msg[JMSG_LENGTH_MAX];
|
||||
eh->err.format_message(cinfo, msg);
|
||||
Console.ErrorFmt("libjpeg fatal error: {}", msg);
|
||||
longjmp(eh->jbuf, 1);
|
||||
};
|
||||
|
||||
if (setjmp(eh->jbuf) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool WrapJPEGDecompress(RGBA8Image* image, T setup_func)
|
||||
{
|
||||
std::vector<u8> scanline;
|
||||
jpeg_decompress_struct info = {};
|
||||
|
||||
JPEGErrorHandler err;
|
||||
if (!HandleJPEGError(&err))
|
||||
// NOTE: Be **very** careful not to allocate memory after calling this function.
|
||||
// It won't get freed, because fastjmp does not unwind the stack.
|
||||
JPEGErrorHandler errhandler;
|
||||
if (fastjmp_set(&errhandler.jbuf) != 0)
|
||||
{
|
||||
jpeg_destroy_decompress(&info);
|
||||
return false;
|
||||
|
||||
jpeg_decompress_struct info;
|
||||
info.err = &err.err;
|
||||
}
|
||||
info.err = &errhandler.err;
|
||||
jpeg_create_decompress(&info);
|
||||
setup_func(info);
|
||||
|
||||
@@ -541,13 +543,17 @@ template <typename T>
|
||||
static bool WrapJPEGCompress(const RGBA8Image& image, u8 quality, T setup_func)
|
||||
{
|
||||
std::vector<u8> scanline;
|
||||
jpeg_compress_struct info = {};
|
||||
|
||||
JPEGErrorHandler err;
|
||||
if (!HandleJPEGError(&err))
|
||||
// NOTE: Be **very** careful not to allocate memory after calling this function.
|
||||
// It won't get freed, because fastjmp does not unwind the stack.
|
||||
JPEGErrorHandler errhandler;
|
||||
if (fastjmp_set(&errhandler.jbuf) != 0)
|
||||
{
|
||||
jpeg_destroy_compress(&info);
|
||||
return false;
|
||||
|
||||
jpeg_compress_struct info;
|
||||
info.err = &err.err;
|
||||
}
|
||||
info.err = &errhandler.err;
|
||||
jpeg_create_compress(&info);
|
||||
setup_func(info);
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
#include <QtWidgets/QStyledItemDelegate>
|
||||
|
||||
static const char* SUPPORTED_FORMATS_STRING = QT_TRANSLATE_NOOP(GameListWidget,
|
||||
".bin/.iso (ISO Disc Images)\n"
|
||||
@@ -95,6 +97,40 @@ private:
|
||||
QString m_filter_name;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class GameListIconStyleDelegate final : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
GameListIconStyleDelegate(QWidget* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
~GameListIconStyleDelegate() = default;
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
|
||||
{
|
||||
// https://stackoverflow.com/questions/32216568/how-to-set-icon-center-in-qtableview
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
// draw default item
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption(&opt, index);
|
||||
opt.icon = QIcon();
|
||||
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
|
||||
|
||||
const QRect r = option.rect;
|
||||
const QPixmap pix = qvariant_cast<QPixmap>(index.data(Qt::DecorationRole));
|
||||
const int pix_width = static_cast<int>(pix.width() / pix.devicePixelRatio());
|
||||
const int pix_height = static_cast<int>(pix.width() / pix.devicePixelRatio());
|
||||
|
||||
// draw pixmap at center of item
|
||||
const QPoint p = QPoint((r.width() - pix_width) / 2, (r.height() - pix_height) / 2);
|
||||
painter->drawPixmap(r.topLeft() + p, pix);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
GameListWidget::GameListWidget(QWidget* parent /* = nullptr */)
|
||||
: QWidget(parent)
|
||||
{
|
||||
@@ -152,6 +188,7 @@ void GameListWidget::initialize()
|
||||
m_table_view->verticalHeader()->hide();
|
||||
m_table_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_table_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
m_table_view->setItemDelegateForColumn(0, new GameListIconStyleDelegate(this));
|
||||
|
||||
loadTableViewColumnVisibilitySettings();
|
||||
loadTableViewColumnSortSettings();
|
||||
@@ -537,7 +574,10 @@ void GameListWidget::loadTableViewColumnSortSettings()
|
||||
.value_or(DEFAULT_SORT_COLUMN);
|
||||
const bool sort_descending =
|
||||
Host::GetBaseBoolSettingValue("GameListTableView", "SortDescending", DEFAULT_SORT_DESCENDING);
|
||||
m_table_view->sortByColumn(sort_column, sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder);
|
||||
const Qt::SortOrder sort_order = sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder;
|
||||
m_sort_model->sort(sort_column, sort_order);
|
||||
if (QHeaderView* hv = m_table_view->horizontalHeader())
|
||||
hv->setSortIndicator(sort_column, sort_order);
|
||||
}
|
||||
|
||||
void GameListWidget::saveTableViewColumnSortSettings()
|
||||
|
||||
@@ -586,6 +586,10 @@ void MainWindow::quit()
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
// Big picture might still be active.
|
||||
if (m_display_created)
|
||||
g_emu_thread->stopFullscreenUI();
|
||||
|
||||
// Ensure subwindows are removed before quitting. That way the log window cancelling
|
||||
// the close event won't cancel the quit process.
|
||||
destroySubWindows();
|
||||
@@ -1360,7 +1364,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
{
|
||||
connect(menu.addAction(tr("Check Wiki Page")), &QAction::triggered, [this, entry]() { goToWikiPage(entry); });
|
||||
}
|
||||
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
if (!s_vm_valid)
|
||||
|
||||
@@ -45,23 +45,33 @@ void QtHost::UpdateApplicationTheme()
|
||||
SetIconThemeFromStyle();
|
||||
}
|
||||
|
||||
bool QtHost::IsDarkApplicationTheme()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
return (palette.windowText().color().value() > palette.window().color().value());
|
||||
}
|
||||
|
||||
void QtHost::SetIconThemeFromStyle()
|
||||
{
|
||||
const bool dark = IsDarkApplicationTheme();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
|
||||
void QtHost::SetStyleFromSettings()
|
||||
{
|
||||
const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", GetDefaultThemeName()));
|
||||
|
||||
// setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it
|
||||
// is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes.
|
||||
qApp->setPalette(QPalette(s_unthemed_palette));
|
||||
|
||||
if (theme == "fusion")
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else if (theme == "windowsvista")
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("windowsvista"));
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
#endif
|
||||
@@ -98,6 +108,7 @@ void QtHost::SetStyleFromSettings()
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "darkfusionblue")
|
||||
{
|
||||
@@ -132,6 +143,7 @@ void QtHost::SetStyleFromSettings()
|
||||
darkBluePalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkBluePalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "GreyMatter")
|
||||
{
|
||||
@@ -167,6 +179,7 @@ void QtHost::SetStyleFromSettings()
|
||||
greyMatterPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(greyMatterPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "UntouchedLagoon")
|
||||
{
|
||||
@@ -201,6 +214,7 @@ void QtHost::SetStyleFromSettings()
|
||||
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
|
||||
|
||||
qApp->setPalette(untouchedLagoonPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "BabyPastel")
|
||||
{
|
||||
@@ -237,6 +251,7 @@ void QtHost::SetStyleFromSettings()
|
||||
babyPastelPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(babyPastelPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "PizzaBrown")
|
||||
{
|
||||
@@ -273,6 +288,7 @@ void QtHost::SetStyleFromSettings()
|
||||
pizzaPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
|
||||
|
||||
qApp->setPalette(pizzaPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "PCSX2Blue")
|
||||
{
|
||||
@@ -307,6 +323,7 @@ void QtHost::SetStyleFromSettings()
|
||||
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
|
||||
|
||||
qApp->setPalette(pcsx2BluePalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "ScarletDevilRed")
|
||||
{
|
||||
@@ -339,6 +356,7 @@ void QtHost::SetStyleFromSettings()
|
||||
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
|
||||
|
||||
qApp->setPalette(scarletDevilPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
@@ -371,6 +389,7 @@ void QtHost::SetStyleFromSettings()
|
||||
violetAngelPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
|
||||
|
||||
qApp->setPalette(violetAngelPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
@@ -407,6 +426,7 @@ void QtHost::SetStyleFromSettings()
|
||||
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(cobaltSkyPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "Ruby")
|
||||
{
|
||||
@@ -439,6 +459,7 @@ void QtHost::SetStyleFromSettings()
|
||||
rubyPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(rubyPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "Sapphire")
|
||||
{
|
||||
@@ -471,6 +492,7 @@ void QtHost::SetStyleFromSettings()
|
||||
sapphirePalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(sapphirePalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "Emerald")
|
||||
{
|
||||
@@ -503,6 +525,7 @@ void QtHost::SetStyleFromSettings()
|
||||
emeraldPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(emeraldPalette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "Custom")
|
||||
{
|
||||
@@ -525,18 +548,7 @@ void QtHost::SetStyleFromSettings()
|
||||
else
|
||||
{
|
||||
qApp->setStyle(s_unthemed_style_name);
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
}
|
||||
|
||||
bool QtHost::IsDarkApplicationTheme()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
return (palette.windowText().color().value() > palette.window().color().value());
|
||||
}
|
||||
|
||||
void QtHost::SetIconThemeFromStyle()
|
||||
{
|
||||
const bool dark = IsDarkApplicationTheme();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -199,6 +199,7 @@ namespace Achievements
|
||||
static std::string s_game_hash;
|
||||
static std::string s_game_title;
|
||||
static std::string s_game_icon;
|
||||
static std::string s_game_icon_url;
|
||||
static u32 s_game_crc;
|
||||
static rc_client_user_game_summary_t s_game_summary;
|
||||
static u32 s_game_id = 0;
|
||||
@@ -401,6 +402,10 @@ const std::string& Achievements::GetRichPresenceString()
|
||||
return s_rich_presence_string;
|
||||
}
|
||||
|
||||
const std::string& Achievements::GetGameIconURL()
|
||||
{
|
||||
return s_game_icon_url;
|
||||
}
|
||||
|
||||
bool Achievements::Initialize()
|
||||
{
|
||||
@@ -945,6 +950,7 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
|
||||
s_has_leaderboards = has_leaderboards;
|
||||
s_has_rich_presence = rc_client_has_rich_presence(client);
|
||||
s_game_icon = {};
|
||||
s_game_icon_url = {};
|
||||
|
||||
// ensure fullscreen UI is ready for notifications
|
||||
MTGS::RunOnGSThread(&ImGuiManager::InitializeFullscreenUI);
|
||||
@@ -966,6 +972,16 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
|
||||
}
|
||||
}
|
||||
|
||||
char icon_url[64];
|
||||
if (int err = rc_client_game_get_image_url(info, icon_url, std::size(icon_url)); err == RC_OK)
|
||||
{
|
||||
s_game_icon_url = icon_url;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportRCError(err, "rc_client_game_get_image_url() failed: ");
|
||||
}
|
||||
|
||||
UpdateGameSummary();
|
||||
DisplayAchievementSummary();
|
||||
|
||||
@@ -990,6 +1006,7 @@ void Achievements::ClearGameInfo()
|
||||
s_game_id = 0;
|
||||
s_game_title = {};
|
||||
s_game_icon = {};
|
||||
s_game_icon_url = {};
|
||||
s_has_achievements = false;
|
||||
s_has_leaderboards = false;
|
||||
s_has_rich_presence = false;
|
||||
|
||||
@@ -108,6 +108,10 @@ namespace Achievements
|
||||
/// Should be called with the lock held.
|
||||
const std::string& GetRichPresenceString();
|
||||
|
||||
/// Returns the current game icon url.
|
||||
/// Should be called with the lock held.
|
||||
const std::string& GetGameIconURL();
|
||||
|
||||
/// Returns the RetroAchievements title for the current game.
|
||||
/// Should be called with the lock held.
|
||||
const std::string& GetGameTitle();
|
||||
|
||||
@@ -379,8 +379,7 @@ set(pcsx2USBSources
|
||||
USB/usb-lightgun/guncon2.cpp
|
||||
USB/usb-mic/audiodev-cubeb.cpp
|
||||
USB/usb-mic/usb-headset.cpp
|
||||
USB/usb-mic/usb-mic-logitech.cpp
|
||||
USB/usb-mic/usb-mic-singstar.cpp
|
||||
USB/usb-mic/usb-mic.cpp
|
||||
USB/usb-msd/usb-msd.cpp
|
||||
USB/usb-pad/lg/lg_ff.cpp
|
||||
USB/usb-pad/usb-buzz.cpp
|
||||
@@ -418,7 +417,7 @@ set(pcsx2USBHeaders
|
||||
USB/usb-mic/audiodev-noop.h
|
||||
USB/usb-mic/audiodev.h
|
||||
USB/usb-mic/usb-headset.h
|
||||
USB/usb-mic/usb-mic-singstar.h
|
||||
USB/usb-mic/usb-mic.h
|
||||
USB/usb-msd/usb-msd.h
|
||||
USB/usb-pad/lg/lg_ff.h
|
||||
USB/usb-pad/usb-buzz.h
|
||||
|
||||
@@ -4420,13 +4420,35 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
// Per pixel alpha blending
|
||||
if (m_draw_env->PABE.PABE && GetAlphaMinMax().min < 128)
|
||||
{
|
||||
// Breath of Fire Dragon Quarter, Strawberry Shortcake, Super Robot Wars, Cartoon Network Racing, Simple 2000 Series Vol.81, SOTC, Super Robot Wars.
|
||||
if (sw_blending)
|
||||
// Breath of Fire Dragon Quarter, Strawberry Shortcake, Super Robot Wars, Cartoon Network Racing, Simple 2000 Series Vol.81, SOTC.
|
||||
if (GetAlphaMinMax().max == 128 && m_conf.ps.blend_a == 0 && ((blend.dst == GSDevice::INV_SRC1_COLOR)
|
||||
|| (blend.dst == GSDevice::INV_DST_ALPHA)
|
||||
|| (blend.dst == GSDevice::INV_CONST_COLOR)))
|
||||
{
|
||||
GL_INS("PABE mode ENABLED");
|
||||
if (features.texture_barrier)
|
||||
// PABE disable blending:
|
||||
// We can disable blending here as an optimization since alpha max is 128
|
||||
// which if alpha is 1 in the formula Cs*Alpha + Cd*(1 - Alpha) will give us a result of Cs.
|
||||
m_conf.blend = {};
|
||||
m_conf.ps.no_color1 = true;
|
||||
m_conf.ps.blend_a = m_conf.ps.blend_b = m_conf.ps.blend_c = m_conf.ps.blend_d = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (sw_blending)
|
||||
{
|
||||
if (accumulation_blend && (blend.op != GSDevice::OP_REV_SUBTRACT))
|
||||
{
|
||||
// Disable hw/sw blend and do pure sw blend with reading the framebuffer.
|
||||
// PABE accumulation blend:
|
||||
// Idea is to achieve final output Cs when As < 1, we do this with manipulating Cd using the src1 output.
|
||||
// This can't be done with reverse subtraction as we want Cd to be 0 when As < 1.
|
||||
// TODO: Blend mix is excluded as no games were found, otherwise it can be added.
|
||||
|
||||
m_conf.ps.pabe = 1;
|
||||
}
|
||||
else if (features.texture_barrier)
|
||||
{
|
||||
// PABE sw blend:
|
||||
// Disable hw/sw mix and do pure sw blend with reading the framebuffer.
|
||||
color_dest_blend = false;
|
||||
accumulation_blend = false;
|
||||
blend_mix = false;
|
||||
@@ -4441,8 +4463,11 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
}
|
||||
else
|
||||
{
|
||||
// PABE sw blend:
|
||||
m_conf.ps.pabe = !(accumulation_blend || blend_mix);
|
||||
}
|
||||
|
||||
GL_INS("PABE mode %s", m_conf.ps.pabe ? "ENABLED" : "DISABLED");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4516,9 +4541,13 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
m_conf.ps.blend_b = 2;
|
||||
}
|
||||
}
|
||||
else if (m_conf.ps.pabe)
|
||||
{
|
||||
m_conf.blend.dst_factor = GSDevice::SRC1_COLOR;
|
||||
}
|
||||
|
||||
// Dual source output not needed (accumulation blend replaces it with ONE).
|
||||
m_conf.ps.no_color1 = true;
|
||||
m_conf.ps.no_color1 = (m_conf.ps.pabe == 0);
|
||||
}
|
||||
else if (blend_mix)
|
||||
{
|
||||
|
||||
@@ -925,9 +925,15 @@ struct PSMain
|
||||
// PABE
|
||||
if (PS_PABE)
|
||||
{
|
||||
// As_rgba needed for accumulation blend to manipulate Cd.
|
||||
// No blending so early exit
|
||||
if (As < 1.f)
|
||||
{
|
||||
As_rgba.rgb = float3(0.f);
|
||||
return;
|
||||
}
|
||||
|
||||
As_rgba.rgb = float3(1.f);
|
||||
}
|
||||
|
||||
float Ad = PS_RTA_CORRECTION ? trunc(current_color.a * 128.1f) / 128.f : trunc(current_color.a * 255.1f) / 128.f;
|
||||
|
||||
@@ -2344,6 +2344,11 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
||||
swap_chain_texture->OverrideImageLayout(GSTextureVK::Layout::Undefined);
|
||||
swap_chain_texture->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::ColorAttachment);
|
||||
|
||||
// Present render pass gets started out here, so we can't transition source textures in DoStretchRect
|
||||
// Make sure they're ready now
|
||||
if (!frame_skip && m_current)
|
||||
static_cast<GSTextureVK*>(m_current)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
|
||||
const VkFramebuffer fb = swap_chain_texture->GetFramebuffer(false);
|
||||
if (fb == VK_NULL_HANDLE)
|
||||
return GSDevice::PresentResult::FrameSkipped;
|
||||
|
||||
@@ -924,9 +924,16 @@ void GSDownloadTextureVK::Flush()
|
||||
|
||||
// Need to execute command buffer.
|
||||
if (GSDeviceVK::GetInstance()->GetCurrentFenceCounter() == m_copy_fence_counter)
|
||||
{
|
||||
if (GSDeviceVK::GetInstance()->InRenderPass())
|
||||
GSDeviceVK::GetInstance()->EndRenderPass();
|
||||
|
||||
GSDeviceVK::GetInstance()->ExecuteCommandBufferForReadback();
|
||||
}
|
||||
else
|
||||
{
|
||||
GSDeviceVK::GetInstance()->WaitForFenceCounter(m_copy_fence_counter);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
||||
@@ -1863,7 +1863,9 @@ void ImGuiFullscreen::PopulateFileSelectorItems()
|
||||
{
|
||||
FileSystem::FindResultsArray results;
|
||||
FileSystem::FindFiles(s_file_selector_current_directory.c_str(), "*",
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &results);
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_HIDDEN_FILES |
|
||||
FILESYSTEM_FIND_RELATIVE_PATHS | FILESYSTEM_FIND_SORT_BY_NAME,
|
||||
&results);
|
||||
|
||||
std::string parent_path;
|
||||
std::string::size_type sep_pos = s_file_selector_current_directory.rfind(FS_OSPATH_SEPARATOR_CHARACTER);
|
||||
@@ -2679,16 +2681,17 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||
continue;
|
||||
}
|
||||
|
||||
const ImVec2 title_size(text_font->CalcTextSizeA(title_font->FontSize, max_text_width, max_text_width,
|
||||
const ImVec2 title_size(title_font->CalcTextSizeA(title_font->FontSize, max_text_width, max_text_width,
|
||||
notif.title.c_str(), notif.title.c_str() + notif.title.size()));
|
||||
|
||||
const ImVec2 text_size(text_font->CalcTextSizeA(text_font->FontSize, max_text_width, max_text_width,
|
||||
notif.text.c_str(), notif.text.c_str() + notif.text.size()));
|
||||
|
||||
const float box_width = std::max(
|
||||
(horizontal_padding * 2.0f) + badge_size + horizontal_spacing + std::max(title_size.x, text_size.x), min_width);
|
||||
const float box_width = std::max((horizontal_padding * 2.0f) + badge_size + horizontal_spacing +
|
||||
ImCeil(std::max(title_size.x, text_size.x)),
|
||||
min_width);
|
||||
const float box_height =
|
||||
std::max((vertical_padding * 2.0f) + title_size.y + vertical_spacing + text_size.y, min_height);
|
||||
std::max((vertical_padding * 2.0f) + ImCeil(title_size.y) + vertical_spacing + ImCeil(text_size.y), min_height);
|
||||
|
||||
u8 opacity;
|
||||
if (time_passed < NOTIFICATION_FADE_IN_TIME)
|
||||
|
||||
@@ -755,9 +755,21 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
|
||||
float actual_y = msg.last_y;
|
||||
if (msg.target_y != expected_y)
|
||||
{
|
||||
if (msg.last_y < 0.0f)
|
||||
{
|
||||
// First showing.
|
||||
msg.last_y = expected_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We got repositioned, probably due to another message above getting removed.
|
||||
const float time_since_move =
|
||||
static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - msg.move_time));
|
||||
const float frac = Easing::OutExpo(time_since_move / MOVE_DURATION);
|
||||
msg.last_y = std::floor(msg.last_y - ((msg.last_y - msg.target_y) * frac));
|
||||
}
|
||||
msg.move_time = current_time;
|
||||
msg.target_y = expected_y;
|
||||
msg.last_y = (msg.last_y < 0.0f) ? expected_y : msg.last_y;
|
||||
actual_y = msg.last_y;
|
||||
}
|
||||
else if (actual_y != expected_y)
|
||||
@@ -773,7 +785,7 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
|
||||
else
|
||||
{
|
||||
const float frac = Easing::OutExpo(time_since_move / MOVE_DURATION);
|
||||
actual_y = msg.last_y - ((msg.last_y - msg.target_y) * frac);
|
||||
actual_y = std::floor(msg.last_y - ((msg.last_y - msg.target_y) * frac));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ namespace EmuFolders
|
||||
std::string Videos;
|
||||
|
||||
static bool ShouldUsePortableMode();
|
||||
static std::string GetPortableModePath();
|
||||
} // namespace EmuFolders
|
||||
|
||||
TraceFiltersEE::TraceFiltersEE()
|
||||
@@ -1910,6 +1911,14 @@ bool EmuFolders::ShouldUsePortableMode()
|
||||
return FileSystem::FileExists(Path::Combine(AppRoot, "portable.ini").c_str()) || FileSystem::FileExists(Path::Combine(AppRoot, "portable.txt").c_str());
|
||||
}
|
||||
|
||||
std::string EmuFolders::GetPortableModePath()
|
||||
{
|
||||
const auto portable_txt_path = Path::Combine(AppRoot, "portable.txt");
|
||||
const auto portable_path = FileSystem::ReadFileToString(portable_txt_path.c_str()).value_or("");
|
||||
const auto trimmed_path = StringUtil::StripWhitespace(portable_path);
|
||||
return std::string(trimmed_path);
|
||||
}
|
||||
|
||||
bool EmuFolders::SetDataDirectory(Error* error)
|
||||
{
|
||||
if (!ShouldUsePortableMode())
|
||||
@@ -1954,7 +1963,7 @@ bool EmuFolders::SetDataDirectory(Error* error)
|
||||
|
||||
// couldn't determine the data directory, or using portable mode? fallback to portable.
|
||||
if (DataRoot.empty())
|
||||
DataRoot = AppRoot;
|
||||
DataRoot = Path::Combine(AppRoot, GetPortableModePath());
|
||||
|
||||
// inis is always below the data root
|
||||
Settings = Path::Combine(DataRoot, "inis");
|
||||
|
||||
@@ -473,7 +473,8 @@ std::vector<std::string> Pad::GetInputProfileNames()
|
||||
{
|
||||
FileSystem::FindResultsArray results;
|
||||
FileSystem::FindFiles(EmuFolders::InputProfiles.c_str(), "*.ini",
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS,
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS |
|
||||
FILESYSTEM_FIND_SORT_BY_NAME,
|
||||
&results);
|
||||
|
||||
std::vector<std::string> ret;
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 55;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 56;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "usb-pad/usb-realplay.h"
|
||||
#include "usb-hid/usb-hid.h"
|
||||
#include "usb-mic/usb-headset.h"
|
||||
#include "usb-mic/usb-mic-singstar.h"
|
||||
#include "usb-mic/usb-mic.h"
|
||||
#include "usb-msd/usb-msd.h"
|
||||
#include "usb-pad/usb-pad.h"
|
||||
#include "usb-pad/usb-trance-vibrator.h"
|
||||
@@ -68,8 +68,7 @@ void RegisterDevice::Register()
|
||||
return;
|
||||
inst.Add(DEVTYPE_PAD, new usb_pad::PadDevice());
|
||||
inst.Add(DEVTYPE_MSD, new usb_msd::MsdDevice());
|
||||
inst.Add(DEVTYPE_SINGSTAR, new usb_mic::SingstarDevice());
|
||||
inst.Add(DEVTYPE_LOGITECH_MIC, new usb_mic::LogitechMicDevice());
|
||||
inst.Add(DEVTYPE_MICROPHONE, new usb_mic::MicrophoneDevice());
|
||||
inst.Add(DEVTYPE_LOGITECH_HEADSET, new usb_mic::HeadsetDevice());
|
||||
inst.Add(DEVTYPE_HIDKEYBOARD, new usb_hid::HIDKbdDevice());
|
||||
inst.Add(DEVTYPE_HIDMOUSE, new usb_hid::HIDMouseDevice());
|
||||
|
||||
@@ -26,8 +26,7 @@ enum DeviceType : s32
|
||||
DEVTYPE_NONE = -1,
|
||||
DEVTYPE_PAD = 0,
|
||||
DEVTYPE_MSD,
|
||||
DEVTYPE_SINGSTAR,
|
||||
DEVTYPE_LOGITECH_MIC,
|
||||
DEVTYPE_MICROPHONE,
|
||||
DEVTYPE_LOGITECH_HEADSET,
|
||||
DEVTYPE_HIDKEYBOARD,
|
||||
DEVTYPE_HIDMOUSE,
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "usb-eyetoy-webcam.h"
|
||||
#include "ov519.h"
|
||||
#include "USB/qemu-usb/desc.h"
|
||||
#include "USB/usb-mic/audio.h"
|
||||
#include "USB/usb-mic/usb-mic.h"
|
||||
#include "USB/USB.h"
|
||||
#include "StateWrapper.h"
|
||||
|
||||
@@ -23,7 +25,7 @@ namespace usb_eyetoy
|
||||
u32 subtype;
|
||||
|
||||
std::unique_ptr<VideoDevice> videodev;
|
||||
// struct freeze {
|
||||
USBDevice* mic;
|
||||
uint8_t regs[0xFF]; //OV519
|
||||
uint8_t i2c_regs[0xFF]; //OV764x
|
||||
|
||||
@@ -32,7 +34,6 @@ namespace usb_eyetoy
|
||||
std::unique_ptr<unsigned char[]> mpeg_frame_data;
|
||||
unsigned int mpeg_frame_size;
|
||||
unsigned int mpeg_frame_offset;
|
||||
// } f;
|
||||
} EYETOYState;
|
||||
|
||||
static const USBDescStrings desc_strings = {
|
||||
@@ -103,8 +104,11 @@ namespace usb_eyetoy
|
||||
|
||||
static void eyetoy_handle_reset(USBDevice* dev)
|
||||
{
|
||||
reset_controller(USB_CONTAINER_OF(dev, EYETOYState, dev));
|
||||
reset_sensor(USB_CONTAINER_OF(dev, EYETOYState, dev));
|
||||
EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev);
|
||||
reset_controller(s);
|
||||
reset_sensor(s);
|
||||
if (s->mic)
|
||||
s->mic->klass.handle_reset(s->mic);
|
||||
}
|
||||
|
||||
static void webcam_handle_control_eyetoy(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data)
|
||||
@@ -328,10 +332,8 @@ namespace usb_eyetoy
|
||||
}
|
||||
else if (devep == 2)
|
||||
{
|
||||
// get audio
|
||||
//Console.Warning("get audio %d\n", len);
|
||||
memset(data, 0, std::min(p->buffer_size, max_ep_size));
|
||||
usb_packet_copy(p, data, std::min(p->buffer_size, max_ep_size));
|
||||
if (s->mic)
|
||||
s->mic->klass.handle_data(s->mic, p);
|
||||
}
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
@@ -408,11 +410,18 @@ namespace usb_eyetoy
|
||||
{
|
||||
EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev);
|
||||
close_camera(s);
|
||||
if (s->mic)
|
||||
s->mic->klass.unrealize(s->mic);
|
||||
delete s;
|
||||
}
|
||||
|
||||
USBDevice* EyeToyWebCamDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
|
||||
{
|
||||
const usb_mic::MicrophoneDevice* mic_proxy =
|
||||
static_cast<usb_mic::MicrophoneDevice*>(RegisterDevice::instance().Device(DEVTYPE_MICROPHONE));
|
||||
if (!mic_proxy)
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<VideoDevice> videodev(VideoDevice::CreateInstance());
|
||||
if (!videodev)
|
||||
{
|
||||
@@ -435,6 +444,8 @@ namespace usb_eyetoy
|
||||
goto fail;
|
||||
s->dev.klass.handle_control = webcam_handle_control_eyetoy;
|
||||
s->dev.klass.handle_data = webcam_handle_data_eyetoy;
|
||||
|
||||
s->mic = mic_proxy->CreateDevice(si, port, 0, false, 16000, TypeName());
|
||||
}
|
||||
else if (subtype == TYPE_OV511P)
|
||||
{
|
||||
@@ -503,17 +514,42 @@ namespace usb_eyetoy
|
||||
std::span<const char*> EyeToyWebCamDevice::SubTypes() const
|
||||
{
|
||||
static const char* subtypes[] = {
|
||||
TRANSLATE_NOOP("USB", "Sony EyeToy"), TRANSLATE_NOOP("USB", "Konami Capture Eye")};
|
||||
TRANSLATE_NOOP("USB", "Sony EyeToy"),
|
||||
TRANSLATE_NOOP("USB", "Konami Capture Eye")
|
||||
};
|
||||
return subtypes;
|
||||
}
|
||||
|
||||
std::span<const SettingInfo> EyeToyWebCamDevice::Settings(u32 subtype) const
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "device_name", TRANSLATE_NOOP("USB", "Device Name"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to capture images from."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &VideoDevice::GetDeviceList},
|
||||
};
|
||||
return info;
|
||||
switch (subtype)
|
||||
{
|
||||
case TYPE_EYETOY:
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "device_name", TRANSLATE_NOOP("USB", "Video Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to capture images from."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &VideoDevice::GetDeviceList},
|
||||
{SettingInfo::Type::StringList, "input_device_name", TRANSLATE_NOOP("USB", "Audio Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to read audio from."), "", nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::Integer, "input_latency", TRANSLATE_NOOP("USB", "Audio Latency"),
|
||||
TRANSLATE_NOOP("USB", "Specifies the latency to the host input device."),
|
||||
AudioDevice::DEFAULT_LATENCY_STR, "1", "1000", "1", TRANSLATE_NOOP("USB", "%dms"), nullptr, nullptr, 1.0f},
|
||||
};
|
||||
return info;
|
||||
}
|
||||
case TYPE_OV511P:
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "device_name", TRANSLATE_NOOP("USB", "Video Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to capture images from."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &VideoDevice::GetDeviceList},
|
||||
};
|
||||
return info;
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
} // namespace usb_eyetoy
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "usb-mic-singstar.h"
|
||||
#include "audio.h"
|
||||
#include "USB/qemu-usb/desc.h"
|
||||
#include "USB/qemu-usb/USBinternal.h"
|
||||
|
||||
namespace usb_mic
|
||||
{
|
||||
static const uint8_t logitech_mic_dev_descriptor[] = {
|
||||
/* bLength */ 0x12, //(18)
|
||||
/* bDescriptorType */ 0x01, //(1)
|
||||
/* bcdUSB */ WBVAL(0x0110), //(272)
|
||||
/* bDeviceClass */ 0x00, //(0)
|
||||
/* bDeviceSubClass */ 0x00, //(0)
|
||||
/* bDeviceProtocol */ 0x00, //(0)
|
||||
/* bMaxPacketSize0 */ 0x08, //(8)
|
||||
/* idVendor */ WBVAL(0x046D),
|
||||
/* idProduct */ WBVAL(0x0000), //(0)
|
||||
/* bcdDevice */ WBVAL(0x0001), //(1)
|
||||
/* iManufacturer */ 0x01, //(1)
|
||||
/* iProduct */ 0x02, //(2)
|
||||
/* iSerialNumber */ 0x00, //(0) unused
|
||||
/* bNumConfigurations */ 0x01, //(1)
|
||||
|
||||
};
|
||||
|
||||
static const uint8_t logitech_mic_config_descriptor[] = {
|
||||
|
||||
/* Configuration 1 */
|
||||
0x09, /* bLength */
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
WBVAL(0x00b1), /* wTotalLength */
|
||||
0x02, /* bNumInterfaces */
|
||||
0x01, /* bConfigurationValue */
|
||||
0x00, /* iConfiguration */
|
||||
USB_CONFIG_BUS_POWERED, /* bmAttributes */
|
||||
USB_CONFIG_POWER_MA(90), /* bMaxPower */
|
||||
|
||||
/* Interface 0, Alternate Setting 0, Audio Control */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x00, /* bInterfaceNumber */
|
||||
0x00, /* bAlternateSetting */
|
||||
0x00, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Control Interface */
|
||||
AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
|
||||
WBVAL(0x0100), /* 1.00 */ /* bcdADC */
|
||||
WBVAL(0x0028), /* wTotalLength */
|
||||
0x01, /* bInCollection */
|
||||
0x01, /* baInterfaceNr */
|
||||
|
||||
/* Audio Input Terminal */
|
||||
AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
|
||||
0x01, /* bTerminalID */
|
||||
WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */
|
||||
0x02, /* bAssocTerminal */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL(AUDIO_CHANNEL_L | AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
0x00, /* iChannelNames */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Audio Output Terminal */
|
||||
AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalID */
|
||||
WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */
|
||||
0x01, /* bAssocTerminal */
|
||||
0x03, /* bSourceID */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Audio Feature Unit */
|
||||
AUDIO_FEATURE_UNIT_DESC_SZ(2, 1), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
|
||||
0x03, /* bUnitID */
|
||||
0x01, /* bSourceID */
|
||||
0x01, /* bControlSize */
|
||||
0x01, /* bmaControls(0) */
|
||||
0x02, /* bmaControls(1) */
|
||||
0x02, /* bmaControls(2) */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x00, /* bAlternateSetting */
|
||||
0x00, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Interface 1, Alternate Setting 1, Audio Streaming - Operational */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x01, /* bAlternateSetting */
|
||||
0x01, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Streaming Interface */
|
||||
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalLink */
|
||||
0x01, /* bDelay */
|
||||
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
||||
|
||||
/* Audio Type I Format */
|
||||
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
||||
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
||||
0x01, /* bNrChannels */
|
||||
0x02, /* bSubFrameSize */
|
||||
0x10, /* bBitResolution */
|
||||
0x05, /* bSamFreqType */
|
||||
B3VAL(8000), /* tSamFreq 1 */
|
||||
B3VAL(11025), /* tSamFreq 2 */
|
||||
B3VAL(22050), /* tSamFreq 3 */
|
||||
B3VAL(44100), /* tSamFreq 4 */
|
||||
B3VAL(48000), /* tSamFreq 5 */
|
||||
|
||||
/* Endpoint - Standard Descriptor */
|
||||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x0064), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
0x00, /* bSynchAddress */
|
||||
|
||||
/* Endpoint - Audio Streaming */
|
||||
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
||||
0x01, /* bmAttributes */
|
||||
0x00, /* bLockDelayUnits */
|
||||
WBVAL(0x0000), /* wLockDelay */
|
||||
|
||||
/* Interface 1, Alternate Setting 2, Audio Streaming - ? */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x02, /* bAlternateSetting */
|
||||
0x01, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Streaming Interface */
|
||||
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalLink */
|
||||
0x01, /* bDelay */
|
||||
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
||||
|
||||
/* Audio Type I Format */
|
||||
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
||||
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
||||
0x02, /* bNrChannels */
|
||||
0x02, /* bSubFrameSize */
|
||||
0x10, /* bBitResolution */
|
||||
0x05, /* bSamFreqType */
|
||||
B3VAL(8000), /* tSamFreq 1 */
|
||||
B3VAL(11025), /* tSamFreq 2 */
|
||||
B3VAL(22050), /* tSamFreq 3 */
|
||||
B3VAL(44100), /* tSamFreq 4 */
|
||||
B3VAL(48000), /* tSamFreq 5 */
|
||||
|
||||
/* Endpoint - Standard Descriptor */
|
||||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x00c8), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
0x00, /* bSynchAddress */
|
||||
|
||||
/* Endpoint - Audio Streaming */
|
||||
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
||||
0x01, /* bmAttributes */
|
||||
0x00, /* bLockDelayUnits */
|
||||
WBVAL(0x0000), /* wLockDelay */
|
||||
|
||||
/* Terminator */
|
||||
0 /* bLength */
|
||||
};
|
||||
|
||||
static const USBDescStrings lt_desc_strings = {
|
||||
"",
|
||||
"Logitech",
|
||||
"USBMIC",
|
||||
};
|
||||
|
||||
//Minified state
|
||||
struct SINGSTARMICMINIState
|
||||
{
|
||||
USBDevice dev;
|
||||
|
||||
USBDesc desc;
|
||||
USBDescDevice desc_dev;
|
||||
};
|
||||
|
||||
USBDevice* LogitechMicDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
|
||||
{
|
||||
USBDevice* dev = SingstarDevice::CreateDevice(si, port, subtype, false, LogitechMicDevice::TypeName());
|
||||
if (!dev)
|
||||
return nullptr;
|
||||
|
||||
SINGSTARMICMINIState* s = USB_CONTAINER_OF(dev, SINGSTARMICMINIState, dev);
|
||||
s->desc = {};
|
||||
s->desc_dev = {};
|
||||
|
||||
s->desc.str = lt_desc_strings;
|
||||
s->desc.full = &s->desc_dev;
|
||||
|
||||
if (usb_desc_parse_dev(logitech_mic_dev_descriptor, sizeof(logitech_mic_dev_descriptor), s->desc, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
if (usb_desc_parse_config(logitech_mic_config_descriptor, sizeof(logitech_mic_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = lt_desc_strings[2];
|
||||
usb_desc_init(&s->dev);
|
||||
return dev;
|
||||
fail:
|
||||
s->dev.klass.unrealize(dev);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace usb_mic
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "USB/qemu-usb/qusb.h"
|
||||
#include "USB/qemu-usb/desc.h"
|
||||
#include "USB/qemu-usb/USBinternal.h"
|
||||
#include "USB/usb-mic/usb-mic-singstar.h"
|
||||
#include "USB/usb-mic/usb-mic.h"
|
||||
#include "USB/usb-mic/audiodev.h"
|
||||
#include "USB/usb-mic/audiodev-noop.h"
|
||||
#include "USB/usb-mic/audiodev-cubeb.h"
|
||||
@@ -55,13 +55,13 @@ namespace usb_mic
|
||||
{
|
||||
|
||||
/*
|
||||
* A USB audio device supports an arbitrary number of alternate
|
||||
* interface settings for each interface. Each corresponds to a block
|
||||
* diagram of parameterized blocks. This can thus refer to things like
|
||||
* number of channels, data rates, or in fact completely different
|
||||
* block diagrams. Alternative setting 0 is always the null block diagram,
|
||||
* which is used by a disabled device.
|
||||
*/
|
||||
* A USB audio device supports an arbitrary number of alternate
|
||||
* interface settings for each interface. Each corresponds to a block
|
||||
* diagram of parameterized blocks. This can thus refer to things like
|
||||
* number of channels, data rates, or in fact completely different
|
||||
* block diagrams. Alternative setting 0 is always the null block diagram,
|
||||
* which is used by a disabled device.
|
||||
*/
|
||||
enum usb_audio_altset : int8_t
|
||||
{
|
||||
ALTSET_OFF = 0x00, /* No endpoint */
|
||||
@@ -93,15 +93,27 @@ namespace usb_mic
|
||||
//uint8_t fifo[2][200]; //on-chip 400byte fifo
|
||||
};
|
||||
|
||||
static const USBDescStrings desc_strings = {
|
||||
static const USBDescStrings singstar_desc_strings = {
|
||||
"",
|
||||
"Nam Tai E&E Products Ltd.",
|
||||
"USBMIC",
|
||||
"310420811",
|
||||
};
|
||||
|
||||
static const USBDescStrings logitech_desc_strings = {
|
||||
"",
|
||||
"Logitech",
|
||||
"USBMIC",
|
||||
};
|
||||
|
||||
static const USBDescStrings ak5370_desc_strings = {
|
||||
"",
|
||||
"AKM",
|
||||
"AK5370"
|
||||
};
|
||||
|
||||
/* descriptor dumped from a real singstar MIC adapter */
|
||||
static const uint8_t singstar_mic_dev_descriptor[] = {
|
||||
static const uint8_t singstar_dev_descriptor[] = {
|
||||
/* bLength */ 0x12, //(18)
|
||||
/* bDescriptorType */ 0x01, //(1)
|
||||
/* bcdUSB */ WBVAL(0x0110), //(272)
|
||||
@@ -116,11 +128,9 @@ namespace usb_mic
|
||||
/* iProduct */ 0x02, //(2)
|
||||
/* iSerialNumber */ 0x00, //(0) unused
|
||||
/* bNumConfigurations */ 0x01, //(1)
|
||||
|
||||
};
|
||||
|
||||
static const uint8_t singstar_mic_config_descriptor[] = {
|
||||
|
||||
static const uint8_t singstar_config_descriptor[] = {
|
||||
/* Configuration 1 */
|
||||
0x09, /* bLength */
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
@@ -196,7 +206,7 @@ namespace usb_mic
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Interface 1, Alternate Setting 1, Audio Streaming - Operational */
|
||||
/* Interface 1, Alternate Setting 1, Audio Streaming - 1 channel */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
@@ -248,7 +258,7 @@ namespace usb_mic
|
||||
0x00, /* bLockDelayUnits */
|
||||
WBVAL(0x0000), /* wLockDelay */
|
||||
|
||||
/* Interface 1, Alternate Setting 2, Audio Streaming - ? */
|
||||
/* Interface 1, Alternate Setting 2, Audio Streaming - 2 channels */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
@@ -304,8 +314,337 @@ namespace usb_mic
|
||||
0 /* bLength */
|
||||
};
|
||||
|
||||
static const uint8_t logitech_dev_descriptor[] = {
|
||||
/* bLength */ 0x12, //(18)
|
||||
/* bDescriptorType */ 0x01, //(1)
|
||||
/* bcdUSB */ WBVAL(0x0110), //(272)
|
||||
/* bDeviceClass */ 0x00, //(0)
|
||||
/* bDeviceSubClass */ 0x00, //(0)
|
||||
/* bDeviceProtocol */ 0x00, //(0)
|
||||
/* bMaxPacketSize0 */ 0x08, //(8)
|
||||
/* idVendor */ WBVAL(0x046D),
|
||||
/* idProduct */ WBVAL(0x0000), //(0)
|
||||
/* bcdDevice */ WBVAL(0x0001), //(1)
|
||||
/* iManufacturer */ 0x01, //(1)
|
||||
/* iProduct */ 0x02, //(2)
|
||||
/* iSerialNumber */ 0x00, //(0) unused
|
||||
/* bNumConfigurations */ 0x01, //(1)
|
||||
};
|
||||
|
||||
static void singstar_mic_handle_reset(USBDevice* dev)
|
||||
static const uint8_t logitech_config_descriptor[] = {
|
||||
/* Configuration 1 */
|
||||
0x09, /* bLength */
|
||||
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
WBVAL(0x00b1), /* wTotalLength */
|
||||
0x02, /* bNumInterfaces */
|
||||
0x01, /* bConfigurationValue */
|
||||
0x00, /* iConfiguration */
|
||||
USB_CONFIG_BUS_POWERED, /* bmAttributes */
|
||||
USB_CONFIG_POWER_MA(90), /* bMaxPower */
|
||||
|
||||
/* Interface 0, Alternate Setting 0, Audio Control */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x00, /* bInterfaceNumber */
|
||||
0x00, /* bAlternateSetting */
|
||||
0x00, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Control Interface */
|
||||
AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
|
||||
WBVAL(0x0100), /* 1.00 */ /* bcdADC */
|
||||
WBVAL(0x0028), /* wTotalLength */
|
||||
0x01, /* bInCollection */
|
||||
0x01, /* baInterfaceNr */
|
||||
|
||||
/* Audio Input Terminal */
|
||||
AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
|
||||
0x01, /* bTerminalID */
|
||||
WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */
|
||||
0x02, /* bAssocTerminal */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL(AUDIO_CHANNEL_L | AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
0x00, /* iChannelNames */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Audio Output Terminal */
|
||||
AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalID */
|
||||
WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */
|
||||
0x01, /* bAssocTerminal */
|
||||
0x03, /* bSourceID */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Audio Feature Unit */
|
||||
AUDIO_FEATURE_UNIT_DESC_SZ(2, 1), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
|
||||
0x03, /* bUnitID */
|
||||
0x01, /* bSourceID */
|
||||
0x01, /* bControlSize */
|
||||
0x01, /* bmaControls(0) */
|
||||
0x02, /* bmaControls(1) */
|
||||
0x02, /* bmaControls(2) */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
/* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x00, /* bAlternateSetting */
|
||||
0x00, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Interface 1, Alternate Setting 1, Audio Streaming - 1 channel */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x01, /* bAlternateSetting */
|
||||
0x01, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Streaming Interface */
|
||||
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalLink */
|
||||
0x01, /* bDelay */
|
||||
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
||||
|
||||
/* Audio Type I Format */
|
||||
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
||||
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
||||
0x01, /* bNrChannels */
|
||||
0x02, /* bSubFrameSize */
|
||||
0x10, /* bBitResolution */
|
||||
0x05, /* bSamFreqType */
|
||||
B3VAL(8000), /* tSamFreq 1 */
|
||||
B3VAL(11025), /* tSamFreq 2 */
|
||||
B3VAL(22050), /* tSamFreq 3 */
|
||||
B3VAL(44100), /* tSamFreq 4 */
|
||||
B3VAL(48000), /* tSamFreq 5 */
|
||||
|
||||
/* Endpoint - Standard Descriptor */
|
||||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x0064), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
0x00, /* bSynchAddress */
|
||||
|
||||
/* Endpoint - Audio Streaming */
|
||||
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
||||
0x01, /* bmAttributes */
|
||||
0x00, /* bLockDelayUnits */
|
||||
WBVAL(0x0000), /* wLockDelay */
|
||||
|
||||
/* Interface 1, Alternate Setting 2, Audio Streaming - 2 channels */
|
||||
USB_INTERFACE_DESC_SIZE, /* bLength */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x01, /* bInterfaceNumber */
|
||||
0x02, /* bAlternateSetting */
|
||||
0x01, /* bNumEndpoints */
|
||||
USB_CLASS_AUDIO, /* bInterfaceClass */
|
||||
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface */
|
||||
|
||||
/* Audio Streaming Interface */
|
||||
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
||||
0x02, /* bTerminalLink */
|
||||
0x01, /* bDelay */
|
||||
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
||||
|
||||
/* Audio Type I Format */
|
||||
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
||||
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
||||
0x02, /* bNrChannels */
|
||||
0x02, /* bSubFrameSize */
|
||||
0x10, /* bBitResolution */
|
||||
0x05, /* bSamFreqType */
|
||||
B3VAL(8000), /* tSamFreq 1 */
|
||||
B3VAL(11025), /* tSamFreq 2 */
|
||||
B3VAL(22050), /* tSamFreq 3 */
|
||||
B3VAL(44100), /* tSamFreq 4 */
|
||||
B3VAL(48000), /* tSamFreq 5 */
|
||||
|
||||
/* Endpoint - Standard Descriptor */
|
||||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x00c8), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
0x00, /* bSynchAddress */
|
||||
|
||||
/* Endpoint - Audio Streaming */
|
||||
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
||||
0x01, /* bmAttributes */
|
||||
0x00, /* bLockDelayUnits */
|
||||
WBVAL(0x0000), /* wLockDelay */
|
||||
|
||||
/* Terminator */
|
||||
0 /* bLength */
|
||||
};
|
||||
|
||||
static const uint8_t ak5370_dev_descriptor[] = {
|
||||
0x12, // bLength
|
||||
0x01, // bDescriptorType (Device)
|
||||
0x10, 0x01, // bcdUSB 1.10
|
||||
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
|
||||
0x00, // bDeviceSubClass
|
||||
0x00, // bDeviceProtocol
|
||||
0x08, // bMaxPacketSize0 8
|
||||
0x56, 0x05, // idVendor 0x0556
|
||||
0x01, 0x00, // idProduct 0x0001
|
||||
0x01, 0x00, // bcdDevice 0.01
|
||||
0x01, // iManufacturer (String Index)
|
||||
0x02, // iProduct (String Index)
|
||||
0x00, // iSerialNumber (String Index)
|
||||
0x01, // bNumConfigurations 1
|
||||
};
|
||||
|
||||
static const uint8_t ak5370_config_descriptor[] = {
|
||||
0x09, // bLength
|
||||
0x02, // bDescriptorType (Configuration)
|
||||
0x76, 0x00, // wTotalLength 118
|
||||
0x02, // bNumInterfaces 2
|
||||
0x01, // bConfigurationValue
|
||||
0x00, // iConfiguration (String Index)
|
||||
0x80, // bmAttributes
|
||||
0x2D, // bMaxPower 90mA
|
||||
|
||||
0x09, // bLength
|
||||
0x04, // bDescriptorType (Interface)
|
||||
0x00, // bInterfaceNumber 0
|
||||
0x00, // bAlternateSetting
|
||||
0x00, // bNumEndpoints 0
|
||||
0x01, // bInterfaceClass (Audio)
|
||||
0x01, // bInterfaceSubClass (Audio Control)
|
||||
0x00, // bInterfaceProtocol
|
||||
0x00, // iInterface (String Index)
|
||||
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
|
||||
0x00, 0x01, // bcdADC 1.00
|
||||
0x26, 0x00, // wTotalLength 38
|
||||
0x01, // binCollection 0x01
|
||||
0x01, // baInterfaceNr 1
|
||||
|
||||
0x0C, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
|
||||
0x01, // bTerminalID
|
||||
0x01, 0x02, // wTerminalType (Microphone)
|
||||
0x02, // bAssocTerminal
|
||||
0x01, // bNrChannels 1
|
||||
0x00, 0x00, // wChannelConfig
|
||||
0x00, // iChannelNames
|
||||
0x00, // iTerminal
|
||||
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
|
||||
0x02, // bTerminalID
|
||||
0x01, 0x01, // wTerminalType (USB Streaming)
|
||||
0x01, // bAssocTerminal
|
||||
0x03, // bSourceID
|
||||
0x00, // iTerminal
|
||||
|
||||
0x08, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
|
||||
0x03, // bUnitID
|
||||
0x01, // bSourceID
|
||||
0x01, // bControlSize 1
|
||||
0x43, 0x00, // bmaControls[0] (Mute,Volume,Automatic)
|
||||
|
||||
0x09, // bLength
|
||||
0x04, // bDescriptorType (Interface)
|
||||
0x01, // bInterfaceNumber 1
|
||||
0x00, // bAlternateSetting
|
||||
0x00, // bNumEndpoints 0
|
||||
0x01, // bInterfaceClass (Audio)
|
||||
0x02, // bInterfaceSubClass (Audio Streaming)
|
||||
0x00, // bInterfaceProtocol
|
||||
0x00, // iInterface (String Index)
|
||||
|
||||
0x09, // bLength
|
||||
0x04, // bDescriptorType (Interface)
|
||||
0x01, // bInterfaceNumber 1
|
||||
0x01, // bAlternateSetting
|
||||
0x01, // bNumEndpoints 1
|
||||
0x01, // bInterfaceClass (Audio)
|
||||
0x02, // bInterfaceSubClass (Audio Streaming)
|
||||
0x00, // bInterfaceProtocol
|
||||
0x00, // iInterface (String Index)
|
||||
|
||||
0x07, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
|
||||
0x02, // bTerminalLink
|
||||
0x01, // bDelay 1
|
||||
0x01, 0x00, // wFormatTag (PCM)
|
||||
|
||||
0x17, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
|
||||
0x01, // bFormatType 1
|
||||
0x01, // bNrChannels (Mono)
|
||||
0x02, // bSubFrameSize 2
|
||||
0x10, // bBitResolution 16
|
||||
0x05, // bSamFreqType 5
|
||||
0x40, 0x1F, 0x00, // tSamFreq[1] 8000 Hz
|
||||
0x11, 0x2B, 0x00, // tSamFreq[2] 11025 Hz
|
||||
0x22, 0x56, 0x00, // tSamFreq[3] 22050 Hz
|
||||
0x44, 0xAC, 0x00, // tSamFreq[4] 44100 Hz
|
||||
0x80, 0xBB, 0x00, // tSamFreq[5] 48000 Hz
|
||||
|
||||
0x07, // bLength
|
||||
0x05, // bDescriptorType (See Next Line)
|
||||
0x81, // bEndpointAddress (IN/D2H)
|
||||
0x01, // bmAttributes (Isochronous, No Sync, Data EP)
|
||||
0x64, 0x00, // wMaxPacketSize 100
|
||||
0x01, // bInterval 1 (unit depends on device speed)
|
||||
|
||||
0x07, // bLength
|
||||
0x25, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
|
||||
0x01, // bmAttributes (Sampling Freq Control)
|
||||
0x00, // bLockDelayUnits
|
||||
0x00, 0x00, // wLockDelay 0
|
||||
};
|
||||
|
||||
static void usb_mic_handle_reset(USBDevice* dev)
|
||||
{
|
||||
/* XXX: do it */
|
||||
return;
|
||||
@@ -320,9 +659,9 @@ namespace usb_mic
|
||||
//0x0300 - feature bUnitID 0x03
|
||||
static int usb_audio_get_control(SINGSTARMICState* s, uint8_t attrib, uint16_t cscn, uint16_t idif, int length, uint8_t* data)
|
||||
{
|
||||
uint8_t cs = cscn >> 8;
|
||||
uint8_t cn = cscn - 1; /* -1 for the non-present master control */
|
||||
uint32_t aid = ATTRIB_ID(cs, attrib, idif);
|
||||
const uint8_t cs = cscn >> 8;
|
||||
const uint8_t cn = cscn - 1; /* -1 for the non-present master control */
|
||||
const uint32_t aid = ATTRIB_ID(cs, attrib, idif);
|
||||
int ret = USB_RET_STALL;
|
||||
|
||||
switch (aid)
|
||||
@@ -332,17 +671,16 @@ namespace usb_mic
|
||||
ret = 1;
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0300):
|
||||
if (cn < 2)
|
||||
if (cn < 2 || cn == 0xff)
|
||||
{
|
||||
//uint16_t vol = (s->f.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
|
||||
uint16_t vol = (s->f.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
|
||||
const uint16_t vol = (s->f.vol[cn == 1 ? 1 : 0] * 0x8800 + 127) / 255 + 0x8000;
|
||||
data[0] = (uint8_t)(vol & 0xFF);
|
||||
data[1] = vol >> 8;
|
||||
ret = 2;
|
||||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_MIN, 0x0300):
|
||||
if (cn < 2)
|
||||
if (cn < 2 || cn == 0xff)
|
||||
{
|
||||
data[0] = 0x01;
|
||||
data[1] = 0x80;
|
||||
@@ -352,7 +690,7 @@ namespace usb_mic
|
||||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_MAX, 0x0300):
|
||||
if (cn < 2)
|
||||
if (cn < 2 || cn == 0xff)
|
||||
{
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x08;
|
||||
@@ -362,7 +700,7 @@ namespace usb_mic
|
||||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_RES, 0x0300):
|
||||
if (cn < 2)
|
||||
if (cn < 2 || cn == 0xff)
|
||||
{
|
||||
data[0] = 0x88;
|
||||
data[1] = 0x00;
|
||||
@@ -390,7 +728,7 @@ namespace usb_mic
|
||||
ret = 0;
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0300):
|
||||
if (cn < 2)
|
||||
if (cn < 2 || cn == 0xff)
|
||||
{
|
||||
uint16_t vol = data[0] + (data[1] << 8);
|
||||
|
||||
@@ -400,12 +738,25 @@ namespace usb_mic
|
||||
if (vol > 255)
|
||||
vol = 255;
|
||||
|
||||
if (s->f.vol[cn] != vol)
|
||||
s->f.vol[cn] = (uint8_t)vol;
|
||||
if (cn == 0xff)
|
||||
{
|
||||
if (s->f.vol[0] != vol)
|
||||
s->f.vol[0] = (uint8_t)vol;
|
||||
if (s->f.vol[1] != vol)
|
||||
s->f.vol[1] = (uint8_t)vol;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->f.vol[cn] != vol)
|
||||
s->f.vol[cn] = (uint8_t)vol;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_AUTOMATIC_GAIN_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0300):
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -418,32 +769,41 @@ namespace usb_mic
|
||||
uint32_t aid = ATTRIB_ID(cs, attrib, ep);
|
||||
int ret = USB_RET_STALL;
|
||||
|
||||
//cs 1 cn 0xFF, ep 0x81 attrib 1
|
||||
Console.Warning("singstar: ep control cs %x, cn %X, %X %X data:", cs, cn, attrib, ep);
|
||||
Console.Warning("usb_mic: ep control: cs=0x%x, cn=0x%X, attrib=0x%X, ep=0x%X", cs, cn, attrib, ep);
|
||||
/*for(int i=0; i<length; i++)
|
||||
Console.Warning("%02X ", data[i]);
|
||||
Console.Warning("\n");*/
|
||||
Console.Warning("\n");*/
|
||||
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_SAMPLING_FREQ_CONTROL, AUDIO_REQUEST_SET_CUR, 0x81):
|
||||
if (cn == 0xFF)
|
||||
{
|
||||
s->f.srate[0] = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
s->f.srate[1] = s->f.srate[0];
|
||||
const uint32_t sr = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
if (s->f.srate[0] != sr)
|
||||
{
|
||||
s->f.srate[0] = sr;
|
||||
if (s->audsrc[0])
|
||||
s->audsrc[0]->SetResampling(s->f.srate[0]);
|
||||
|
||||
if (s->audsrc[0])
|
||||
s->audsrc[0]->SetResampling(s->f.srate[0]);
|
||||
|
||||
if (s->audsrc[1])
|
||||
s->audsrc[1]->SetResampling(s->f.srate[1]);
|
||||
}
|
||||
if (s->f.srate[1] != sr)
|
||||
{
|
||||
s->f.srate[1] = sr;
|
||||
if (s->audsrc[1])
|
||||
s->audsrc[1]->SetResampling(s->f.srate[1]);
|
||||
|
||||
}
|
||||
}
|
||||
else if (cn < 2)
|
||||
{
|
||||
|
||||
s->f.srate[cn] = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
if (s->audsrc[cn])
|
||||
s->audsrc[cn]->SetResampling(s->f.srate[cn]);
|
||||
const uint32_t sr = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
if (s->f.srate[cn] != sr)
|
||||
{
|
||||
s->f.srate[cn] = sr;
|
||||
if (s->audsrc[cn])
|
||||
s->audsrc[cn]->SetResampling(s->f.srate[cn]);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -458,7 +818,7 @@ namespace usb_mic
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void singstar_mic_set_interface(USBDevice* dev, int intf, int alt_old, int alt_new)
|
||||
static void usb_mic_set_interface(USBDevice* dev, int intf, int alt_old, int alt_new)
|
||||
{
|
||||
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
|
||||
s->f.intf = alt_new;
|
||||
@@ -472,7 +832,7 @@ namespace usb_mic
|
||||
#endif
|
||||
}
|
||||
|
||||
static void singstar_mic_handle_control(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data)
|
||||
static void usb_mic_handle_control(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data)
|
||||
{
|
||||
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
|
||||
int ret = 0;
|
||||
@@ -487,8 +847,8 @@ namespace usb_mic
|
||||
switch (request)
|
||||
{
|
||||
/*
|
||||
* Audio device specific request
|
||||
*/
|
||||
* Audio device specific request
|
||||
*/
|
||||
case ClassInterfaceRequest | AUDIO_REQUEST_GET_CUR:
|
||||
case ClassInterfaceRequest | AUDIO_REQUEST_GET_MIN:
|
||||
case ClassInterfaceRequest | AUDIO_REQUEST_GET_MAX:
|
||||
@@ -496,7 +856,7 @@ namespace usb_mic
|
||||
ret = usb_audio_get_control(s, request & 0xff, value, index, length, data);
|
||||
if (ret < 0)
|
||||
{
|
||||
Console.Warning("singstar: fail: get control\n");
|
||||
Console.Warning("usb_mic: fail: get control, req=%02x, val=%02x, idx=%02x, ret=%d", request, value, index, ret);
|
||||
goto fail;
|
||||
}
|
||||
p->actual_length = ret;
|
||||
@@ -509,7 +869,7 @@ namespace usb_mic
|
||||
ret = usb_audio_set_control(s, request & 0xff, value, index, length, data);
|
||||
if (ret < 0)
|
||||
{
|
||||
Console.Warning("singstar: fail: set control\n data:");
|
||||
Console.Warning("usb_mic: fail: set control, req=%02x, val=%02x, idx=%02x", request, value, index);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
@@ -540,28 +900,25 @@ namespace usb_mic
|
||||
return (int16_t)((int32_t)sample * vol / 0xFF);
|
||||
}
|
||||
|
||||
static void singstar_mic_handle_data(USBDevice* dev, USBPacket* p)
|
||||
static void usb_mic_handle_data(USBDevice* dev, USBPacket* p)
|
||||
{
|
||||
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
|
||||
int ret = 0;
|
||||
uint8_t devep = p->ep->nr;
|
||||
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
//Console.Warning("token in ep: %d len: %zd\n", devep, p->iov.size);
|
||||
if (devep == 1)
|
||||
{
|
||||
|
||||
//TODO
|
||||
int outChns = s->f.intf == 1 ? 1 : 2;
|
||||
int outChns = s->f.intf == 2 ? 2 : 1;
|
||||
uint32_t frames, out_frames[2] = {0}, chn;
|
||||
int16_t *src1, *src2;
|
||||
int16_t* dst = (int16_t*)p->buffer_ptr;
|
||||
size_t len = p->buffer_size;
|
||||
|
||||
// send only 1ms (bInterval) of samples
|
||||
if (s->f.srate[0] == 48000 || s->f.srate[0] == 8000)
|
||||
if (s->f.srate[0] == 48000 || s->f.srate[0] == 8000 || s->f.srate[0] == 16000)
|
||||
len = std::min<u32>(p->buffer_size, outChns * sizeof(int16_t) * s->f.srate[0] / 1000);
|
||||
|
||||
//Divide 'len' bytes between 2 channels of 16 bits
|
||||
@@ -661,7 +1018,7 @@ namespace usb_mic
|
||||
if (!file)
|
||||
{
|
||||
char name[1024] = {0};
|
||||
snprintf(name, sizeof(name), "singstar_%dch_%uHz.raw", outChns, s->f.srate[0]);
|
||||
snprintf(name, sizeof(name), "usb_mic_%dch_%uHz.raw", outChns, s->f.srate[0]);
|
||||
file = fopen(name, "wb");
|
||||
}
|
||||
|
||||
@@ -679,7 +1036,7 @@ namespace usb_mic
|
||||
}
|
||||
|
||||
|
||||
static void singstar_mic_handle_destroy(USBDevice* dev)
|
||||
static void usb_mic_handle_destroy(USBDevice* dev)
|
||||
{
|
||||
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
|
||||
if (file)
|
||||
@@ -701,13 +1058,20 @@ namespace usb_mic
|
||||
delete s;
|
||||
}
|
||||
|
||||
USBDevice* SingstarDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
|
||||
USBDevice* MicrophoneDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
|
||||
{
|
||||
return CreateDevice(si, port, subtype, true, SingstarDevice::TypeName());
|
||||
if (subtype >= MIC_COUNT)
|
||||
return nullptr;
|
||||
|
||||
static const bool dual_mic = subtype == MIC_SINGSTAR;
|
||||
return CreateDevice(si, port, subtype, dual_mic, 48000, MicrophoneDevice::TypeName());
|
||||
}
|
||||
|
||||
USBDevice* SingstarDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const char* devtype) const
|
||||
USBDevice* MicrophoneDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const int samplerate, const char* devtype) const
|
||||
{
|
||||
if (subtype >= MIC_COUNT)
|
||||
return nullptr;
|
||||
|
||||
SINGSTARMICState* s = new SINGSTARMICState();
|
||||
|
||||
if (dual_mic)
|
||||
@@ -773,54 +1137,74 @@ namespace usb_mic
|
||||
Host::OSD_ERROR_DURATION);
|
||||
goto fail;
|
||||
}
|
||||
s->audsrc[i]->SetResampling(samplerate);
|
||||
}
|
||||
}
|
||||
|
||||
s->desc.full = &s->desc_dev;
|
||||
s->desc.str = desc_strings;
|
||||
if (usb_desc_parse_dev(singstar_mic_dev_descriptor, sizeof(singstar_mic_dev_descriptor), s->desc, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
if (usb_desc_parse_config(singstar_mic_config_descriptor, sizeof(singstar_mic_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
switch (subtype)
|
||||
{
|
||||
case MIC_SINGSTAR:
|
||||
s->desc.str = singstar_desc_strings;
|
||||
if (usb_desc_parse_dev(singstar_dev_descriptor, sizeof(singstar_dev_descriptor), s->desc, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
if (usb_desc_parse_config(singstar_config_descriptor, sizeof(singstar_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
break;
|
||||
case MIC_LOGITECH:
|
||||
s->desc.str = logitech_desc_strings;
|
||||
if (usb_desc_parse_dev(logitech_dev_descriptor, sizeof(logitech_dev_descriptor), s->desc, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
if (usb_desc_parse_config(logitech_config_descriptor, sizeof(logitech_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
break;
|
||||
case MIC_KONAMI:
|
||||
s->desc.str = ak5370_desc_strings;
|
||||
if (usb_desc_parse_dev(ak5370_dev_descriptor, sizeof(ak5370_dev_descriptor), s->desc, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
if (usb_desc_parse_config(ak5370_config_descriptor, sizeof(ak5370_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = singstar_mic_handle_reset;
|
||||
s->dev.klass.handle_control = singstar_mic_handle_control;
|
||||
s->dev.klass.handle_data = singstar_mic_handle_data;
|
||||
s->dev.klass.set_interface = singstar_mic_set_interface;
|
||||
s->dev.klass.unrealize = singstar_mic_handle_destroy;
|
||||
s->dev.klass.handle_reset = usb_mic_handle_reset;
|
||||
s->dev.klass.handle_control = usb_mic_handle_control;
|
||||
s->dev.klass.handle_data = usb_mic_handle_data;
|
||||
s->dev.klass.set_interface = usb_mic_set_interface;
|
||||
s->dev.klass.unrealize = usb_mic_handle_destroy;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = desc_strings[2];
|
||||
s->dev.klass.product_desc = singstar_desc_strings[2];
|
||||
|
||||
// set defaults
|
||||
s->f.vol[0] = 240; /* 0 dB */
|
||||
s->f.vol[1] = 240; /* 0 dB */
|
||||
s->f.srate[0] = 48000;
|
||||
s->f.srate[1] = 48000;
|
||||
s->f.srate[0] = samplerate;
|
||||
s->f.srate[1] = samplerate;
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
singstar_mic_handle_reset(&s->dev);
|
||||
usb_mic_handle_reset(&s->dev);
|
||||
|
||||
return &s->dev;
|
||||
|
||||
fail:
|
||||
singstar_mic_handle_destroy(&s->dev);
|
||||
usb_mic_handle_destroy(&s->dev);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* SingstarDevice::Name() const
|
||||
const char* MicrophoneDevice::Name() const
|
||||
{
|
||||
return TRANSLATE_NOOP("USB", "Singstar");
|
||||
return TRANSLATE_NOOP("USB", "Microphone");
|
||||
}
|
||||
|
||||
const char* SingstarDevice::TypeName() const
|
||||
const char* MicrophoneDevice::TypeName() const
|
||||
{
|
||||
return "singstar";
|
||||
}
|
||||
|
||||
bool SingstarDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
|
||||
bool MicrophoneDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
|
||||
{
|
||||
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
|
||||
if (!sw.DoMarker("SINGSTARMICState"))
|
||||
@@ -845,48 +1229,55 @@ namespace usb_mic
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
void SingstarDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const
|
||||
void MicrophoneDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const
|
||||
{
|
||||
// TODO: Reload devices.
|
||||
}
|
||||
|
||||
std::span<const SettingInfo> SingstarDevice::Settings(u32 subtype) const
|
||||
std::span<const char*> MicrophoneDevice::SubTypes() const
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "player1_device_name", TRANSLATE_NOOP("USB", "Player 1 Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the input for the first player."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::StringList, "player2_device_name", TRANSLATE_NOOP("USB", "Player 2 Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the input for the second player."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::Integer, "input_latency", TRANSLATE_NOOP("USB", "Input Latency"),
|
||||
TRANSLATE_NOOP("USB", "Specifies the latency to the host input device."),
|
||||
AudioDevice::DEFAULT_LATENCY_STR, "1", "1000", "1", TRANSLATE_NOOP("USB", "%dms"), nullptr, nullptr, 1.0f},
|
||||
static const char* subtypes[] = {
|
||||
TRANSLATE_NOOP("USB", "Singstar"),
|
||||
TRANSLATE_NOOP("USB", "Logitech"),
|
||||
TRANSLATE_NOOP("USB", "Konami"),
|
||||
};
|
||||
return info;
|
||||
return subtypes;
|
||||
}
|
||||
|
||||
const char* LogitechMicDevice::TypeName() const
|
||||
std::span<const SettingInfo> MicrophoneDevice::Settings(u32 subtype) const
|
||||
{
|
||||
return "logitech_usbmic";
|
||||
}
|
||||
|
||||
const char* LogitechMicDevice::Name() const
|
||||
{
|
||||
return TRANSLATE_NOOP("USB", "Logitech USB Mic");
|
||||
}
|
||||
|
||||
std::span<const SettingInfo> LogitechMicDevice::Settings(u32 subtype) const
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "input_device_name", TRANSLATE_NOOP("USB", "Input Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to read audio from."), "", nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::Integer, "input_latency", TRANSLATE_NOOP("USB", "Input Latency"),
|
||||
TRANSLATE_NOOP("USB", "Specifies the latency to the host input device."),
|
||||
AudioDevice::DEFAULT_LATENCY_STR, "1", "1000", "1", TRANSLATE_NOOP("USB", "%dms"), nullptr, nullptr, 1.0f},
|
||||
};
|
||||
return info;
|
||||
switch (subtype)
|
||||
{
|
||||
case MIC_SINGSTAR:
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "player1_device_name", TRANSLATE_NOOP("USB", "Player 1 Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the input for the first player."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::StringList, "player2_device_name", TRANSLATE_NOOP("USB", "Player 2 Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the input for the second player."), "", nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::Integer, "input_latency", TRANSLATE_NOOP("USB", "Input Latency"),
|
||||
TRANSLATE_NOOP("USB", "Specifies the latency to the host input device."),
|
||||
AudioDevice::DEFAULT_LATENCY_STR, "1", "1000", "1", TRANSLATE_NOOP("USB", "%dms"), nullptr, nullptr, 1.0f},
|
||||
};
|
||||
return info;
|
||||
}
|
||||
case MIC_LOGITECH:
|
||||
case MIC_KONAMI:
|
||||
default:
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::StringList, "input_device_name", TRANSLATE_NOOP("USB", "Input Device"),
|
||||
TRANSLATE_NOOP("USB", "Selects the device to read audio from."), "", nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, &AudioDevice::GetInputDeviceList},
|
||||
{SettingInfo::Type::Integer, "input_latency", TRANSLATE_NOOP("USB", "Input Latency"),
|
||||
TRANSLATE_NOOP("USB", "Specifies the latency to the host input device."),
|
||||
AudioDevice::DEFAULT_LATENCY_STR, "1", "1000", "1", TRANSLATE_NOOP("USB", "%dms"), nullptr, nullptr, 1.0f},
|
||||
};
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace usb_mic
|
||||
|
||||
@@ -7,24 +7,24 @@
|
||||
|
||||
namespace usb_mic
|
||||
{
|
||||
class SingstarDevice : public DeviceProxy
|
||||
enum MicrophoneType
|
||||
{
|
||||
MIC_SINGSTAR,
|
||||
MIC_LOGITECH,
|
||||
MIC_KONAMI,
|
||||
MIC_COUNT,
|
||||
};
|
||||
|
||||
class MicrophoneDevice : public DeviceProxy
|
||||
{
|
||||
public:
|
||||
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const char* devtype) const;
|
||||
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const int samplerate, const char* devtype) const;
|
||||
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
|
||||
const char* Name() const override;
|
||||
const char* TypeName() const override;
|
||||
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
|
||||
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
|
||||
std::span<const SettingInfo> Settings(u32 subtype) const override;
|
||||
};
|
||||
|
||||
class LogitechMicDevice final : public SingstarDevice
|
||||
{
|
||||
public:
|
||||
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
|
||||
const char* TypeName() const override;
|
||||
const char* Name() const override;
|
||||
std::span<const char*> SubTypes() const override;
|
||||
std::span<const SettingInfo> Settings(u32 subtype) const override;
|
||||
};
|
||||
} // namespace usb_mic
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Host.h"
|
||||
#include "USB/usb-pad/usb-pad.h"
|
||||
#include "USB/qemu-usb/desc.h"
|
||||
#include "USB/usb-mic/usb-mic-singstar.h"
|
||||
#include "USB/usb-mic/usb-mic.h"
|
||||
#include "USB/USB.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
@@ -388,12 +388,12 @@ namespace usb_pad
|
||||
|
||||
USBDevice* SeamicDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
|
||||
{
|
||||
const usb_mic::SingstarDevice* mic_proxy =
|
||||
static_cast<usb_mic::SingstarDevice*>(RegisterDevice::instance().Device(DEVTYPE_SINGSTAR));
|
||||
const usb_mic::MicrophoneDevice* mic_proxy =
|
||||
static_cast<usb_mic::MicrophoneDevice*>(RegisterDevice::instance().Device(DEVTYPE_MICROPHONE));
|
||||
if (!mic_proxy)
|
||||
return nullptr;
|
||||
|
||||
USBDevice* mic = mic_proxy->CreateDevice(si, port, 0, false, TypeName());
|
||||
USBDevice* mic = mic_proxy->CreateDevice(si, port, 0, false, 48000, TypeName());
|
||||
if (!mic)
|
||||
return nullptr;
|
||||
|
||||
|
||||
@@ -3608,15 +3608,21 @@ void VMManager::UpdateDiscordPresence(bool update_session_time)
|
||||
// https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
|
||||
DiscordRichPresence rp = {};
|
||||
rp.largeImageKey = "4k-pcsx2";
|
||||
rp.largeImageText = "PCSX2 Emulator";
|
||||
rp.largeImageText = "PCSX2 PS2 Emulator";
|
||||
rp.startTimestamp = s_discord_presence_time_epoch;
|
||||
rp.details = s_title.empty() ? TRANSLATE("VMManager","No Game Running") : s_title.c_str();
|
||||
|
||||
std::string state_string;
|
||||
|
||||
if (Achievements::HasRichPresence())
|
||||
{
|
||||
auto lock = Achievements::GetLock();
|
||||
|
||||
state_string = StringUtil::Ellipsise(Achievements::GetRichPresenceString(), 128);
|
||||
rp.state = state_string.c_str();
|
||||
|
||||
rp.largeImageKey = Achievements::GetGameIconURL().c_str();
|
||||
rp.largeImageText = s_title.c_str();
|
||||
}
|
||||
|
||||
Discord_UpdatePresence(&rp);
|
||||
|
||||
@@ -390,8 +390,7 @@
|
||||
<ClCompile Include="USB\usb-lightgun\guncon2.cpp" />
|
||||
<ClCompile Include="USB\usb-mic\audiodev-cubeb.cpp" />
|
||||
<ClCompile Include="USB\usb-mic\usb-headset.cpp" />
|
||||
<ClCompile Include="USB\usb-mic\usb-mic-logitech.cpp" />
|
||||
<ClCompile Include="USB\usb-mic\usb-mic-singstar.cpp" />
|
||||
<ClCompile Include="USB\usb-mic\usb-mic.cpp" />
|
||||
<ClCompile Include="USB\usb-msd\usb-msd.cpp" />
|
||||
<ClCompile Include="USB\usb-pad\lg\lg_ff.cpp" />
|
||||
<ClCompile Include="USB\usb-pad\usb-buzz.cpp" />
|
||||
@@ -844,7 +843,7 @@
|
||||
<ClInclude Include="USB\usb-mic\audiodev-noop.h" />
|
||||
<ClInclude Include="USB\usb-mic\audiodev.h" />
|
||||
<ClInclude Include="USB\usb-mic\usb-headset.h" />
|
||||
<ClInclude Include="USB\usb-mic\usb-mic-singstar.h" />
|
||||
<ClInclude Include="USB\usb-mic\usb-mic.h" />
|
||||
<ClInclude Include="USB\usb-msd\usb-msd.h" />
|
||||
<ClInclude Include="USB\usb-pad\lg\lg_ff.h" />
|
||||
<ClInclude Include="USB\usb-pad\usb-buzz.h" />
|
||||
|
||||
@@ -1178,10 +1178,7 @@
|
||||
<ClCompile Include="USB\usb-mic\usb-headset.cpp">
|
||||
<Filter>System\Ps2\USB\usb-mic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="USB\usb-mic\usb-mic-logitech.cpp">
|
||||
<Filter>System\Ps2\USB\usb-mic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="USB\usb-mic\usb-mic-singstar.cpp">
|
||||
<ClCompile Include="USB\usb-mic\usb-mic.cpp">
|
||||
<Filter>System\Ps2\USB\usb-mic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="USB\usb-hid\usb-hid.cpp">
|
||||
@@ -2127,7 +2124,7 @@
|
||||
<ClInclude Include="USB\usb-mic\usb-headset.h">
|
||||
<Filter>System\Ps2\USB\usb-mic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="USB\usb-mic\usb-mic-singstar.h">
|
||||
<ClInclude Include="USB\usb-mic\usb-mic.h">
|
||||
<Filter>System\Ps2\USB\usb-mic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="USB\usb-mic\audio.h">
|
||||
|
||||
Reference in New Issue
Block a user