Compare commits

...

22 Commits

Author SHA1 Message Date
KamFretoZ
64e17fce3f Qt: Fix a couple of instances of inconsistent sorting
Backport from 7927ec647f
2024-08-24 17:27:39 +02:00
KamFretoZ
518728ca36 Qt: Center type icon in game list
Backport from: 93836636a1
2024-08-24 17:27:39 +02:00
KamFretoZ
d1a7430f80 Qt: Fix incorrect sort indicator on loading
Backport from: a56ebf24b2
2024-08-24 17:27:39 +02:00
KamFretoZ
973c522756 Qt: Ensure fullscreen UI is stopped on exiting
Backport from: 533022bb7d
2024-08-24 17:27:39 +02:00
KamFretoZ
5536342f9d ImGuiManager: Fix stutter when multiple OSD messages lapse
fe55446c25
2024-08-24 17:27:39 +02:00
KamFretoZ
d9ddab1a33 ImGuiFullscreen: Fix incorrect notification width
Backport from: e455a5e371
2024-08-24 17:27:39 +02:00
KamFretoZ
c915aac1fa FileSystem: Correctly use lstat() on Linux
Backport from: 81295c8a7d
2024-08-24 17:27:39 +02:00
KamFretoZ
a3c2a4db5f GSTextureVK: Fix download inside render pass
Backport from: 5f8082734e
2024-08-24 17:27:39 +02:00
KamFretoZ
aebebf5115 Qt: Work around theme switching bug
backport from: b2577ef8bd
2024-08-24 17:27:39 +02:00
KamFretoZ
9a50218400 Image: Fix crash loading corrupted/invalid JPEG files
Backport from: afea18f65e
2024-08-24 17:27:39 +02:00
TellowKrinkle
fd5a652270 Vk: Don't try to transition present source during present 2024-08-23 20:59:26 -05:00
Farran666
c647a30aa9 GameDB: Add multiple fixes 2024-08-23 15:22:51 +02:00
lightningterror
40d5c78573 GS/HW: Implement PABE(Per pixel alpha blending) on accumulation blend and add optimizations.
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.
Blend mix is excluded as no games were found, otherwise it can be added.

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.
2024-08-22 21:39:19 +02:00
xperia64
fe2a9fc2cd GameDB: Correct two Phoenix Games title names 2024-08-22 11:34:51 -04:00
squidbus
83f9add68b Config: Allow specifying portable directory relative path in portable.txt 2024-08-21 12:32:10 -04:00
KamFretoZ
ffe8d16df4 DiscordRPC: Add game icon support. 2024-08-21 12:28:56 -04:00
PCSX2 Bot
31b5672870 Qt: Update Base Translation 2024-08-20 10:11:20 +02:00
Florin9doi
777fc444ae USB: Rename singstar to usb_mic 2024-08-20 10:09:21 +02:00
Florin9doi
cd5c961dc4 USB: Konami ON-SAY microphone emulation 2024-08-20 10:09:21 +02:00
Florin9doi
c2ea8c4eab USB: Audio support for EyeToy 2024-08-20 10:09:21 +02:00
Florin9doi
d6507a945b USB: Merge Singstar and Logitech mics in a single device with 2 subtypes 2024-08-20 10:09:21 +02:00
PCSX2 Bot
f1abee5d0b Qt: Update Base Translation 2024-08-19 09:15:02 +02:00
33 changed files with 1776 additions and 1362 deletions

View File

@@ -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"

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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));
}
}

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;

View File

@@ -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());

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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" />

View File

@@ -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">