Skip to content

Commit

Permalink
Add Audio Dumping to File
Browse files Browse the repository at this point in the history
  • Loading branch information
RisingFog committed Sep 3, 2016
1 parent 78d1af4 commit 645cb4d
Show file tree
Hide file tree
Showing 14 changed files with 240 additions and 5 deletions.
1 change: 1 addition & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ static ConfigSetting generalSettings[] = {
ConfigSetting("ScreenshotsAsPNG", &g_Config.bScreenshotsAsPNG, false, true, true),
ConfigSetting("UseFFV1", &g_Config.bUseFFV1, false),
ConfigSetting("DumpFrames", &g_Config.bDumpFrames, false),
ConfigSetting("DumpAudio", &g_Config.bDumpAudio, false),
ConfigSetting("StateSlot", &g_Config.iCurrentStateSlot, 0, true, true),
ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true),

Expand Down
1 change: 1 addition & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct Config {
bool bScreenshotsAsPNG;
bool bUseFFV1;
bool bDumpFrames;
bool bDumpAudio;
bool bEnableLogging;
bool bDumpDecryptedEboot;
bool bFullscreenOnDoubleclick;
Expand Down
2 changes: 2 additions & 0 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AnySuitable</InlineFunctionExpansion>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AnySuitable</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="WaveFile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\ext\disarm.h" />
Expand Down Expand Up @@ -731,6 +732,7 @@
<ClInclude Include="Util\PPGeDraw.h" />
<ClInclude Include="Util\ppge_atlas.h" />
<ClInclude Include="..\ext\xxhash.h" />
<ClInclude Include="WaveFile.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\android\jni\Android.mk" />
Expand Down
2 changes: 2 additions & 0 deletions Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@
<ClCompile Include="AVIDump.cpp">
<Filter>Core</Filter>
</ClCompile>
<ClCompile Include="WaveFile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
Expand Down Expand Up @@ -1242,6 +1243,7 @@
<ClInclude Include="AVIDump.h">
<Filter>Core</Filter>
</ClInclude>
<ClInclude Include="WaveFile.h" />
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
Expand Down
56 changes: 55 additions & 1 deletion Core/HLE/__sceAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "Core/Host.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Core/HLE/__sceAudio.h"
#include "Core/HLE/sceAudio.h"
#include "Core/HLE/sceKernel.h"
Expand All @@ -54,7 +55,7 @@ enum latency {
};

int eventAudioUpdate = -1;
int eventHostAudioUpdate = -1;
int eventHostAudioUpdate = -1;
int mixFrequency = 44100;

const int hwSampleRate = 44100;
Expand All @@ -67,6 +68,9 @@ static int audioHostIntervalCycles;

static s32 *mixBuffer;

WaveFileWriter g_wave_writer;
bool m_logAudio;

// High and low watermarks, basically. For perfect emulation, the correct values are 0 and 1, respectively.
// TODO: Tweak. Hm, there aren't actually even used currently...
static int chanQueueMaxSizeFactor;
Expand Down Expand Up @@ -134,6 +138,13 @@ void __AudioInit() {

resampler.Clear();
CoreTiming::RegisterMHzChangeCallback(&__AudioCPUMHzChange);

if (g_Config.bDumpAudio)
{
std::string audio_file_name = GetSysDirectory(DIRECTORY_VIDEO_DUMP) + "audiodump.wav";
File::CreateEmptyFile(audio_file_name);
__StartLogAudio(audio_file_name);
}
}

void __AudioDoState(PointerWrap &p) {
Expand Down Expand Up @@ -177,6 +188,11 @@ void __AudioShutdown() {
mixBuffer = 0;
for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++)
chans[i].clear();

if (g_Config.bDumpAudio)
{
__StopLogAudio();
}
}

u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) {
Expand Down Expand Up @@ -364,6 +380,15 @@ void __AudioUpdate() {

if (g_Config.bEnableSound) {
resampler.PushSamples(mixBuffer, hwBlockSize);
if (m_logAudio)
{
s16 *clamped_data = new s16[hwBlockSize * 2];

for (int i = 0; i < hwBlockSize * 2; i++) {
clamped_data[i] = clamp_s16(mixBuffer[i]);
}
g_wave_writer.AddStereoSamples(clamped_data, hwBlockSize);
}
}
}

Expand All @@ -385,3 +410,32 @@ void __PushExternalAudio(const s32 *audio, int numSamples) {
resampler.Clear();
}
}

void __StartLogAudio(const std::string& filename)
{
if (!m_logAudio)
{
m_logAudio = true;
g_wave_writer.Start(filename, 44100);
g_wave_writer.SetSkipSilence(false);
NOTICE_LOG(SCEAUDIO, "Starting Audio logging");
}
else
{
WARN_LOG(SCEAUDIO, "Audio logging has already been started");
}
}

void __StopLogAudio()
{
if (m_logAudio)
{
m_logAudio = false;
g_wave_writer.Stop();
NOTICE_LOG(SCEAUDIO, "Stopping Audio logging");
}
else
{
WARN_LOG(SCEAUDIO, "Audio logging has already been stopped");
}
}
5 changes: 5 additions & 0 deletions Core/HLE/__sceAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#pragma once

#include "sceAudio.h"
#include "Core/WaveFile.h"

struct AudioDebugStats {
int buffered;
Expand Down Expand Up @@ -45,3 +46,7 @@ void __AudioWakeThreads(AudioChannel &chan, int result);
int __AudioMix(short *outstereo, int numSamples, int sampleRate);
const AudioDebugStats *__AudioGetDebugStats();
void __PushExternalAudio(const s32 *audio, int numSamples); // Should not be used in-game, only at the menu!

// Audio Dumping stuff
void __StartLogAudio(const std::string& filename);
void __StopLogAudio();
4 changes: 2 additions & 2 deletions Core/HW/StereoResampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
StereoResampler::StereoResampler()
: m_dma_mixer(this, 44100)
{
// Some Android devices are v-synced to non-60Hz framerates. We simply timestretch audio to fit.
// Some Android devices are v-synced to non-60Hz framerates. We simply timestretch audio to fit.
// TODO: should only do this if auto frameskip is off?

float refresh = System_GetPropertyInt(SYSPROP_DISPLAY_REFRESH_RATE) / 1000.0f;
Expand Down Expand Up @@ -120,7 +120,7 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
if (offset < -MAX_FREQ_SHIFT) offset = -MAX_FREQ_SHIFT;

aid_sample_rate_ = m_input_sample_rate + offset;

/* Hm?
u32 framelimit = SConfig::GetInstance().m_Framelimit;
if (consider_framelimit && framelimit > 1) {
Expand Down
1 change: 1 addition & 0 deletions Core/HW/StereoResampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Core/WaveFile.h"

struct AudioDebugStats;

Expand Down
116 changes: 116 additions & 0 deletions Core/WaveFile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <string>

#include "Core/WaveFile.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Core/Config.h"

constexpr size_t WaveFileWriter::BUFFER_SIZE;

WaveFileWriter::WaveFileWriter()
{
}

WaveFileWriter::~WaveFileWriter()
{
Stop();
}

bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRate)
{
// Check if the file is already open
if (file)
{
PanicAlert("The file %s was already open, the file header will not be written.",
filename.c_str());
return false;
}

file.Open(filename, "wb");
if (!file)
{
PanicAlert("The file %s could not be opened for writing. Please check if it's already opened "
"by another program.",
filename.c_str());
return false;
}

audio_size = 0;

// -----------------
// Write file header
// -----------------
Write4("RIFF");
Write(100 * 1000 * 1000); // write big value in case the file gets truncated
Write4("WAVE");
Write4("fmt ");

Write(16); // size of fmt block
Write(0x00020001); // two channels, uncompressed

const u32 sample_rate = HLESampleRate;
Write(sample_rate);
Write(sample_rate * 2 * 2); // two channels, 16bit

Write(0x00100004);
Write4("data");
Write(100 * 1000 * 1000 - 32);

// We are now at offset 44
if (file.Tell() != 44)
PanicAlert("Wrong offset: %lld", (long long)file.Tell());

return true;
}

void WaveFileWriter::Stop()
{
// u32 file_size = (u32)ftello(file);
file.Seek(4, SEEK_SET);
Write(audio_size + 36);

file.Seek(40, SEEK_SET);
Write(audio_size);

file.Close();
}

void WaveFileWriter::Write(u32 value)
{
file.WriteArray(&value, 1);
}

void WaveFileWriter::Write4(const char* ptr)
{
file.WriteBytes(ptr, 4);
}

void WaveFileWriter::AddStereoSamples(const short* sample_data, u32 count)
{
if (!file)
PanicAlert("WaveFileWriter - file not open.");

if (count > BUFFER_SIZE * 2)
PanicAlert("WaveFileWriter - buffer too small (count = %u).", count);

if (skip_silence)
{
bool all_zero = true;

for (u32 i = 0; i < count * 2; i++)
{
if (sample_data[i])
all_zero = false;
}

if (all_zero)
return;
}

file.WriteBytes(sample_data, count * 4);
audio_size += count * 4;
}
44 changes: 44 additions & 0 deletions Core/WaveFile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

// ---------------------------------------------------------------------------------
// Class: WaveFileWriter
// Description: Simple utility class to make it easy to write long 16-bit stereo
// audio streams to disk.
// Use Start() to start recording to a file, and AddStereoSamples to add wave data.
// The float variant will convert from -1.0-1.0 range and clamp.
// Alternatively, AddSamplesBE for big endian wave data.
// If Stop is not called when it destructs, the destructor will call Stop().
// ---------------------------------------------------------------------------------

#pragma once

#include <array>
#include <string>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"

class WaveFileWriter
{
public:
WaveFileWriter();
~WaveFileWriter();

bool Start(const std::string& filename, unsigned int HLESampleRate);
void Stop();

void SetSkipSilence(bool skip) { skip_silence = skip; }
void AddStereoSamples(const short* sample_data, u32 count);
u32 GetAudioSize() const { return audio_size; }
private:
static constexpr size_t BUFFER_SIZE = 32 * 1024;

File::IOFile file;
bool skip_silence = false;
u32 audio_size = 0;
std::array<short, BUFFER_SIZE> conv_buffer{};
void Write(u32 value);
void Write4(const char* ptr);
};

1 change: 1 addition & 0 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ void GameSettingsScreen::CreateViews() {
systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG")));
systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Dump Frames")));
systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use FFV1 for Frame Dumps")));
systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Dump Audio")));
#endif
systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving")));
static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY"};
Expand Down
6 changes: 6 additions & 0 deletions Windows/MainWindowMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ namespace MainWindow {
// Movie menu
TranslateMenuItem(menu, ID_MOVIE_DUMPFRAMES);
TranslateMenuItem(menu, ID_MOVIE_USEFFV1);
TranslateMenuItem(menu, ID_MOVIE_DUMPAUDIO);

// Skip display multipliers x1-x10
TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, L"\tAlt+Return, F11");
Expand Down Expand Up @@ -942,6 +943,10 @@ namespace MainWindow {
g_Config.bUseFFV1 = !g_Config.bUseFFV1;
break;

case ID_MOVIE_DUMPAUDIO:
g_Config.bDumpAudio = !g_Config.bDumpAudio;
break;

default:
{
// Handle the dynamic shader switching here.
Expand Down Expand Up @@ -982,6 +987,7 @@ namespace MainWindow {
CHECKITEM(ID_OPTIONS_IGNOREWINKEY, g_Config.bIgnoreWindowsKey);
CHECKITEM(ID_MOVIE_DUMPFRAMES, g_Config.bDumpFrames);
CHECKITEM(ID_MOVIE_USEFFV1, g_Config.bUseFFV1);
CHECKITEM(ID_MOVIE_DUMPAUDIO, g_Config.bDumpAudio);

static const int displayrotationitems[] = {
ID_EMULATION_ROTATION_H,
Expand Down
Loading

0 comments on commit 645cb4d

Please sign in to comment.