This commit is contained in:
Stern 2025-12-15 21:56:48 -05:00 committed by GitHub
commit 09f7c5c8e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 111 additions and 11 deletions

View File

@ -191,14 +191,63 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="2" column="0">
<widget class="QLabel" name="audioCaptureVolumeLabel">
<property name="text">
<string>Volume:</string>
</property>
<property name="buddy">
<cstring>audioCaptureVolume</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="audioCaptureVolumeLayout" stretch="1,0">
<item>
<widget class="QSlider" name="audioCaptureVolume">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="tickPosition">
<enum>QSlider::TickPosition::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>25</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="audioCaptureVolumeValue">
<property name="text">
<string>100%</string>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="enableAudioCaptureArguments">
<property name="text">
<string>Extra Arguments</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="audioCaptureArguments"/>
</item>
</layout>
@ -401,6 +450,7 @@
<tabstop>enableAudioCapture</tabstop>
<tabstop>audioCaptureCodec</tabstop>
<tabstop>audioCaptureBitrate</tabstop>
<tabstop>audioCaptureVolume</tabstop>
<tabstop>enableAudioCaptureArguments</tabstop>
<tabstop>audioCaptureArguments</tabstop>
</tabstops>

View File

@ -415,6 +415,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_capture.enableAudioCapture, "EmuCore/GS", "EnableAudioCapture", true);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_capture.audioCaptureBitrate, "EmuCore/GS", "AudioCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_AUDIO_CAPTURE_BITRATE);
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(
sif, m_capture.audioCaptureVolume, m_capture.audioCaptureVolumeValue, "%", "EmuCore/GS", "AudioCaptureVolume", Pcsx2Config::GSOptions::DEFAULT_AUDIO_CAPTURE_VOLUME);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_capture.enableAudioCaptureArguments, "EmuCore/GS", "EnableAudioCaptureParameters", false);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_capture.audioCaptureArguments, "EmuCore/GS", "AudioCaptureParameters");
@ -813,6 +815,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_capture.audioCaptureBitrate, tr("Audio Bitrate"), tr("192 kbps"), tr("Sets the audio bitrate to be used."));
dialog()->registerWidgetHelp(
m_capture.audioCaptureVolume, tr("Audio Volume"), QStringLiteral("100%"),
tr("Sets the volume level for recorded audio. 100% is full volume, lower values reduce the volume."));
dialog()->registerWidgetHelp(m_capture.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"), tr("Allows you to pass arguments to the selected audio codec."));
dialog()->registerWidgetHelp(m_capture.audioCaptureArguments, tr("Extra Audio Arguments"), tr("Leave It Blank"),

View File

@ -704,6 +704,7 @@ struct Pcsx2Config
static constexpr int DEFAULT_VIDEO_CAPTURE_WIDTH = 640;
static constexpr int DEFAULT_VIDEO_CAPTURE_HEIGHT = 480;
static constexpr int DEFAULT_AUDIO_CAPTURE_BITRATE = 192;
static constexpr int DEFAULT_AUDIO_CAPTURE_VOLUME = 100;
static const char* DEFAULT_CAPTURE_CONTAINER;
static constexpr int DEFAULT_SHADEBOOST_BRIGHTNESS = 50;
@ -880,6 +881,7 @@ struct Pcsx2Config
int VideoCaptureWidth = DEFAULT_VIDEO_CAPTURE_WIDTH;
int VideoCaptureHeight = DEFAULT_VIDEO_CAPTURE_HEIGHT;
int AudioCaptureBitrate = DEFAULT_AUDIO_CAPTURE_BITRATE;
int AudioCaptureVolume = DEFAULT_AUDIO_CAPTURE_VOLUME;
std::string Adapter;
std::string HWDumpDirectory;

View File

@ -1148,36 +1148,77 @@ bool GSCapture::ProcessAudioPackets(s64 video_pts)
const u32 contig_frames = std::min(pending_frames, AUDIO_BUFFER_SIZE - s_audio_buffer_read_pos);
const u32 this_batch = std::min(s_audio_frame_size - s_audio_frame_pos, contig_frames);
// Apply volume multiplier
const float volume_scale = static_cast<float>(GSConfig.AudioCaptureVolume) / 100.0f;
// Do we need to convert the sample format?
if (!s_swr_context)
{
// No, just copy frames out of staging buffer.
// No, just copy frames out of staging buffer with volume applied.
if (s_audio_frame_planar)
{
// This is slow. Hopefully doesn't happen in too many configurations.
for (u32 i = 0; i < AUDIO_CHANNELS; i++)
{
u8* output = s_converted_audio_frame->data[i] + s_audio_frame_pos * s_audio_frame_bps;
const u8* input = reinterpret_cast<u8*>(&s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS + i]);
const s16* input = &s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS + i];
for (u32 j = 0; j < this_batch; j++)
{
std::memcpy(output, input, sizeof(s16));
input += sizeof(s16) * AUDIO_CHANNELS;
s16 scaled_input = *input;
if (volume_scale != 1.0f)
{
const float sample = static_cast<float>(scaled_input) * volume_scale;
scaled_input = static_cast<s16>(sample);
}
std::memcpy(output, &scaled_input, sizeof(s16));
input += AUDIO_CHANNELS;
output += s_audio_frame_bps;
}
}
}
else
{
// Direct copy - optimal.
std::memcpy(s_converted_audio_frame->data[0] + s_audio_frame_pos * s_audio_frame_bps * AUDIO_CHANNELS,
&s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS], this_batch * sizeof(s16) * AUDIO_CHANNELS);
// Direct copy with volume optimal.
if (volume_scale != 1.0f)
{
const s16* input = &s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS];
s16* output = reinterpret_cast<s16*>(s_converted_audio_frame->data[0] + s_audio_frame_pos * s_audio_frame_bps * AUDIO_CHANNELS);
for (u32 i = 0; i < this_batch * AUDIO_CHANNELS; i++)
{
const float sample = static_cast<float>(input[i]) * volume_scale;
output[i] = static_cast<s16>(sample);
}
}
else
{
std::memcpy(s_converted_audio_frame->data[0] + s_audio_frame_pos * s_audio_frame_bps * AUDIO_CHANNELS,
&s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS], this_batch * sizeof(s16) * AUDIO_CHANNELS);
}
}
}
else
{
// Use swresample to convert.
const u8* input = reinterpret_cast<u8*>(&s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS]);
// Use swresample to convert. Apply volume to source before conversion.
const s16* input_s16 = &s_audio_buffer[s_audio_buffer_read_pos * AUDIO_CHANNELS];
const u8* input;
if (volume_scale != 1.0f)
{
// Apply volume to source samples before conversion
std::vector<s16> volume_buffer;
volume_buffer.resize(this_batch * AUDIO_CHANNELS);
for (u32 i = 0; i < this_batch * AUDIO_CHANNELS; i++)
{
const float sample = static_cast<float>(input_s16[i]) * volume_scale;
volume_buffer[i] = static_cast<s16>(sample);
}
input = reinterpret_cast<const u8*>(volume_buffer.data());
}
else
{
input = reinterpret_cast<const u8*>(input_s16);
}
// Might be planar, so offset both buffers.
u8* output[AUDIO_CHANNELS];

View File

@ -1072,6 +1072,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitfieldEx(VideoCaptureWidth, "VideoCaptureWidth");
SettingsWrapBitfieldEx(VideoCaptureHeight, "VideoCaptureHeight");
SettingsWrapBitfieldEx(AudioCaptureBitrate, "AudioCaptureBitrate");
SettingsWrapBitfieldEx(AudioCaptureVolume, "AudioCaptureVolume");
SettingsWrapEntry(Adapter);
SettingsWrapEntry(HWDumpDirectory);