Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement audio recording #14817

Merged
merged 20 commits into from Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion 3rdparty/ffmpeg
Submodule ffmpeg updated 36 files
+2 −2 ffmpeg.patch
+ lib/linux/ubuntu-20.04/x86_64/libavcodec.a
+ lib/linux/ubuntu-20.04/x86_64/libavdevice.a
+ lib/linux/ubuntu-20.04/x86_64/libavfilter.a
+ lib/linux/ubuntu-20.04/x86_64/libavformat.a
+ lib/linux/ubuntu-20.04/x86_64/libavutil.a
+ lib/linux/ubuntu-20.04/x86_64/libswresample.a
+ lib/linux/ubuntu-20.04/x86_64/libswscale.a
+ lib/linux/ubuntu-22.04/x86_64/libavcodec.a
+ lib/linux/ubuntu-22.04/x86_64/libavdevice.a
+ lib/linux/ubuntu-22.04/x86_64/libavfilter.a
+ lib/linux/ubuntu-22.04/x86_64/libavformat.a
+ lib/linux/ubuntu-22.04/x86_64/libavutil.a
+ lib/linux/ubuntu-22.04/x86_64/libswresample.a
+ lib/linux/ubuntu-22.04/x86_64/libswscale.a
+ lib/macos/arm64/libavcodec.a
+ lib/macos/arm64/libavdevice.a
+ lib/macos/arm64/libavfilter.a
+ lib/macos/arm64/libavformat.a
+ lib/macos/arm64/libavutil.a
+ lib/macos/arm64/libswresample.a
+ lib/macos/arm64/libswscale.a
+ lib/macos/x86_64/libavcodec.a
+ lib/macos/x86_64/libavdevice.a
+ lib/macos/x86_64/libavfilter.a
+ lib/macos/x86_64/libavformat.a
+ lib/macos/x86_64/libavutil.a
+ lib/macos/x86_64/libswresample.a
+ lib/macos/x86_64/libswscale.a
+ lib/windows/x86_64/avcodec.lib
+ lib/windows/x86_64/avdevice.lib
+ lib/windows/x86_64/avfilter.lib
+ lib/windows/x86_64/avformat.lib
+ lib/windows/x86_64/avutil.lib
+ lib/windows/x86_64/swresample.lib
+ lib/windows/x86_64/swscale.lib
39 changes: 39 additions & 0 deletions rpcs3/Emu/Audio/AudioBackend.h
Expand Up @@ -221,6 +221,45 @@ class AudioBackend
}
}

static void downmix(u32 sample_cnt, u32 src_ch_cnt, u32 dst_ch_cnt, const f32* src, f32* dst)
{
if (src_ch_cnt <= dst_ch_cnt)
{
return;
}

if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_7_1))
{
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1>(sample_cnt, src, dst);
}
else if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
}
}
else if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
{
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
}
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
}
}

protected:
AudioSampleSize m_sample_size = AudioSampleSize::FLOAT;
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
Expand Down
3 changes: 1 addition & 2 deletions rpcs3/Emu/Audio/audio_resampler.cpp
Expand Up @@ -33,8 +33,7 @@ void audio_resampler::put_samples(const f32* buf, u32 sample_cnt)

std::pair<f32* /* buffer */, u32 /* samples */> audio_resampler::get_samples(u32 sample_cnt)
{
f32 *const buf = resampler.bufBegin();
return std::make_pair(buf, resampler.receiveSamples(sample_cnt));
return std::make_pair(resampler.bufBegin(), resampler.receiveSamples(sample_cnt));
}

u32 audio_resampler::samples_available() const
Expand Down
47 changes: 11 additions & 36 deletions rpcs3/Emu/Cell/Modules/cellAudio.cpp
Expand Up @@ -5,6 +5,7 @@
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "cellAudio.h"
#include "util/video_provider.h"

#include <cmath>

Expand Down Expand Up @@ -69,7 +70,7 @@ void cell_audio_config::reset(bool backend_changed)
const AudioFreq freq = AudioFreq::FREQ_48K;
const AudioSampleSize sample_size = raw.convert_to_s16 ? AudioSampleSize::S16 : AudioSampleSize::FLOAT;

const auto [req_ch_cnt, downmix] = AudioBackend::get_channel_count_and_downmixer(0); // CELL_AUDIO_OUT_PRIMARY
const auto& [req_ch_cnt, downmix] = AudioBackend::get_channel_count_and_downmixer(0); // CELL_AUDIO_OUT_PRIMARY
f64 cb_frame_len = 0.0;
u32 ch_cnt = 2;

Expand Down Expand Up @@ -276,52 +277,26 @@ void audio_ringbuffer::process_resampled_data()
{
if (!cfg.time_stretching_enabled) return;

const auto [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt))));
const auto& [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt))));
commit_data(buffer, samples);
}

void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt)
{
sample_cnt *= cfg.audio_channels;
const u32 sample_cnt_in = sample_cnt * cfg.audio_channels;
const u32 sample_cnt_out = sample_cnt * static_cast<u32>(cfg.backend_ch_cnt);

// Dump audio if enabled
m_dump.WriteData(buf, sample_cnt * static_cast<u32>(AudioSampleSize::FLOAT));
m_dump.WriteData(buf, sample_cnt_in * static_cast<u32>(AudioSampleSize::FLOAT));

if (cfg.backend_ch_cnt < AudioChannelCnt{cfg.audio_channels})
// Record audio if enabled
if (utils::video_provider& provider = g_fxo->get<utils::video_provider>(); provider.can_consume_sample())
{
if (AudioChannelCnt{cfg.audio_channels} == AudioChannelCnt::SURROUND_7_1)
{
if (cfg.backend_ch_cnt == AudioChannelCnt::SURROUND_5_1)
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1>(sample_cnt, buf, buf);
}
else if (cfg.backend_ch_cnt == AudioChannelCnt::STEREO)
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO>(sample_cnt, buf, buf);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt));
}
}
else if (AudioChannelCnt{cfg.audio_channels} == AudioChannelCnt::SURROUND_5_1)
{
if (cfg.backend_ch_cnt == AudioChannelCnt::STEREO)
{
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::STEREO>(sample_cnt, buf, buf);
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt));
}
}
else
{
fmt::throw_exception("Invalid downmix combination: %u -> %u", cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt));
}
provider.present_samples(reinterpret_cast<u8*>(buf), sample_cnt, static_cast<u32>(cfg.audio_channels));
}

const u32 sample_cnt_out = sample_cnt / cfg.audio_channels * static_cast<u32>(cfg.backend_ch_cnt);
// Downmix if necessary
AudioBackend::downmix(sample_cnt_in, cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt), buf, buf);

if (cfg.backend->get_convert_to_s16())
{
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/Cell/Modules/cellAudio.h
Expand Up @@ -223,8 +223,8 @@ struct cell_audio_config

AudioChannelCnt audio_downmix = AudioChannelCnt::SURROUND_7_1;
AudioChannelCnt backend_ch_cnt = AudioChannelCnt::SURROUND_7_1;
u32 audio_channels = 0;
u32 audio_sampling_rate = 0;
u32 audio_channels = 2;
u32 audio_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
u32 audio_block_period = 0;
u32 audio_sample_size = 0;
f64 audio_min_buffer_duration = 0.0;
Expand Down