Notice: This version is for testing only. It may cause unwanted side effects for the sound in many games. It adds preliminary support for volume control. I think high delta values (often close to 0x10000) mean that volume should be lowered, and vice versa. But I'm unsure how big the volume steps should be, and where the volume should go to. The current guess is that pb.mixer_control also tell us what the new volume level should be, but I'm not sure about that. The current settings seems to work okay in games like Paper Mario and Fire Emblem when sounds are faded in to begin or faded out to stop. But it worked less well for the sequenced music in Skies of Arcadia where some blocks would get a to high volume.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@806 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2008-10-09 04:00:47 +00:00
parent 3d20ad60d9
commit 4001e11116
6 changed files with 451 additions and 244 deletions

View File

@ -198,7 +198,7 @@ SetTitle(wxT("Sound Debugging"));
m_RadioBox[1] = new wxRadioBox( this, IDC_RADIO1, wxT("Update freq."), m_RadioBox[1] = new wxRadioBox( this, IDC_RADIO1, wxT("Update freq."),
wxDefaultPosition, wxDefaultSize, m_radioBoxNChoices[1], m_radioBoxChoices1, 1, wxRA_SPECIFY_COLS); wxDefaultPosition, wxDefaultSize, m_radioBoxNChoices[1], m_radioBoxChoices1, 1, wxRA_SPECIFY_COLS);
wxString m_radioBoxChoices2[] = { wxT("Preset 1"), wxT("Preset 2"), wxT("Preset 3") }; wxString m_radioBoxChoices2[] = { wxT("Preset 1"), wxT("Updates"), wxT("Looping"), wxT("Mixer") };
m_radioBoxNChoices[2] = sizeof( m_radioBoxChoices2 ) / sizeof( wxString ); m_radioBoxNChoices[2] = sizeof( m_radioBoxChoices2 ) / sizeof( wxString );
m_RadioBox[2] = new wxRadioBox( this, IDC_RADIO2, wxT("Presets"), m_RadioBox[2] = new wxRadioBox( this, IDC_RADIO2, wxT("Presets"),
wxDefaultPosition, wxDefaultSize, m_radioBoxNChoices[2], m_radioBoxChoices2, 1, wxRA_SPECIFY_COLS); wxDefaultPosition, wxDefaultSize, m_radioBoxNChoices[2], m_radioBoxChoices2, 1, wxRA_SPECIFY_COLS);
@ -346,7 +346,7 @@ void CDebugger::DoChangePreset()
} }
else if(m_RadioBox[2]->GetSelection() == 3) else if(m_RadioBox[2]->GetSelection() == 3)
{ {
gPreset = 9; gPreset = 3;
} }
} }
// ============== // ==============

View File

@ -16,7 +16,8 @@
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
// --------------------
// Includes
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#ifdef _WIN32 #ifdef _WIN32
@ -24,40 +25,39 @@
#endif #endif
// --------------------
// On and off // On and off
bool g_consoleEnable = true; bool g_consoleEnable = true;
int gSaveFile = 0; int gSaveFile = 0;
#define DEBUGG #define DEBUGG
//#define DEBUGG_FILEONLY
// -------------------- // --------------------
// Settings
int nFiles = 4;
// --------------------
// Create handles // Create handles
#ifdef DEBUGG #ifdef DEBUGG
FILE* __fStdOut = NULL; FILE* __fStdOut[4]; // you have to update this manually, we can't place a nFiles in there
#endif #endif
#ifndef DEBUGG_FILEONLY
#ifdef _WIN32 #ifdef _WIN32
HANDLE __hStdOut = NULL; HANDLE __hStdOut = NULL;
#endif #endif
#endif
// --------------------
// ======================================================================================= // =======================================================================================
/* Start console window - width and height is the size of console window, if you specify /* Start console window - width and height is the size of console window, if you specify
fname, the output will also be writton to this file. The file pointer is automatically fname, the output will also be written to this file. TODO: Close the file pointer when the app
closed when you close the app */ is closed */
// --------------------------------------------------------------------------------------- // -------------
void startConsoleWin(int width, int height, char* fname) void startConsoleWin(int width, int height, char* fname)
{ {
#if defined(DEBUGG) && defined(_WIN32) #if defined(DEBUGG) && defined(_WIN32)
#ifndef DEBUGG_FILEONLY
AllocConsole(); AllocConsole();
SetConsoleTitle(fname); SetConsoleTitle(fname);
@ -69,53 +69,79 @@ void startConsoleWin(int width, int height, char* fname)
SMALL_RECT coo = {0,0,(width - 1),70}; // top, left, right, bottom SMALL_RECT coo = {0,0,(width - 1),70}; // top, left, right, bottom
SetConsoleWindowInfo(__hStdOut, TRUE, &coo); SetConsoleWindowInfo(__hStdOut, TRUE, &coo);
#endif
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// Write to a file // Write to a file
if(fname) if(fname)
{ {
// Edit the log file name for(int i = 0; i < nFiles; i++)
std::string FileEnding = ".log"; {
std::string FileName = fname; // Edit the log file name
std::string FullFilename = (FileName + FileEnding); std::string FileEnding = ".log";
__fStdOut = fopen(FullFilename.c_str(), "w"); std::string FileName = fname;
char buffer[33]; itoa(i, buffer, 10); // convert number to string
std::string FullFilename = (FileName + buffer + FileEnding);
__fStdOut[i] = fopen(FullFilename.c_str(), "w");
}
} }
// --------------------------------------------------------------------------------------- // ---------------
#endif #endif
} }
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// Printf function // File printf function
int aprintf(int a, char *fmt, ...)
{
#if defined(DEBUGG) && defined(_WIN32)
if(gSaveFile)
{
char s[5000]; // WARNING: mind this value
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(s, 5000, fmt, argptr); // remember to update this value to
va_end(argptr);
// ---------------------------------------------------------------------------------------
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
//to make it work
fprintf(__fStdOut[a], s);
// -------------
return(cnt);
}
else
{
return 0;
}
#else
return 0;
#endif
}
// ---------------------------------------------------------------------------------------
// Printf to screen function
int wprintf(char *fmt, ...) int wprintf(char *fmt, ...)
{ {
#if defined(DEBUGG) && defined(_WIN32) #if defined(DEBUGG) && defined(_WIN32)
char s[7000]; // WARNING: Mind this value char s[5000]; // WARNING: mind this value
va_list argptr; va_list argptr;
int cnt; int cnt;
va_start(argptr, fmt); va_start(argptr, fmt);
cnt = vsnprintf(s, 3000, fmt, argptr); cnt = vsnprintf(s, 5000, fmt, argptr);
va_end(argptr); va_end(argptr);
DWORD cCharsWritten; DWORD cCharsWritten;
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
#ifndef DEBUGG_FILEONLY
if(__hStdOut) if(__hStdOut)
{ {
WriteConsole(__hStdOut, s, strlen(s), &cCharsWritten, NULL); WriteConsole(__hStdOut, s, strlen(s), &cCharsWritten, NULL);
} }
#endif
// -------------
// ---------------------------------------------------------------------------------------
if(gSaveFile)
{
if(__fStdOut)
fprintf(__fStdOut, s);
}
// ------------- // -------------
return(cnt); return(cnt);

View File

@ -18,6 +18,7 @@
void startConsoleWin(int width, int height, char* fname); void startConsoleWin(int width, int height, char* fname);
int wprintf(char *fmt, ...); int wprintf(char *fmt, ...);
int aprintf(int a, char *fmt, ...);
void ClearScreen(); void ClearScreen();
void OpenConsole(); void OpenConsole();
void CloseConsole(); void CloseConsole();

View File

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <string> // so that we can test std::string == abc #include <string> // so that we can test std::string == abc
#include <math.h> // for the pow() function
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#endif #endif
@ -43,6 +44,7 @@
// Externals // Externals
extern int nFiles;
float ratioFactor; // a global to get the ratio factor from MixAdd float ratioFactor; // a global to get the ratio factor from MixAdd
int gUpdFreq = 5; int gUpdFreq = 5;
int gPreset = 0; int gPreset = 0;
@ -57,9 +59,13 @@ extern int gSaveFile;
// Parameter blocks // Parameter blocks
std::vector<u32> gloopPos(64); std::vector<u32> gloopPos(64);
std::vector<u32> gsampleEnd(64); std::vector<u32> gsampleEnd(64);
std::vector<u32> gsamplePos(64); std::vector<u32> gsamplePos(64);
// main
std::vector<u16> gsrc_type(64);
std::vector<u16> gis_stream(64);
// PBSampleRateConverter src // PBSampleRateConverter src
std::vector<u32> gratio(64); std::vector<u32> gratio(64);
@ -70,20 +76,39 @@ std::vector<u32> gsamplePos(64);
// PBSampleRateConverter mixer // PBSampleRateConverter mixer
std::vector<u16> gvolume_left(64); std::vector<u16> gvolume_left(64);
std::vector<u16> gmix_unknown(64);
std::vector<u16> gvolume_right(64); std::vector<u16> gvolume_right(64);
std::vector<u16> gmix_unknown2(64);
std::vector<u16> gmixer_control(64); std::vector<u16> gmixer_control(64);
std::vector<u16> gmixer_vol1(64);
std::vector<u16> gmixer_vol2(64);
std::vector<u16> gmixer_vol3(64);
std::vector<u16> gmixer_vol4(64);
std::vector<u16> gmixer_vol5(64);
std::vector<u16> gmixer_vol6(64);
std::vector<u16> gmixer_vol7(64);
std::vector<u16> gmixer_d1(64);
std::vector<u16> gmixer_d2(64);
std::vector<u16> gmixer_d3(64);
std::vector<u16> gmixer_d4(64);
std::vector<u16> gmixer_d5(64);
std::vector<u16> gmixer_d6(64);
std::vector<u16> gmixer_d7(64);
// PBVolumeEnvelope vol_env
std::vector<u16> gcur_volume(64); std::vector<u16> gcur_volume(64);
std::vector<u16> gcur_volume_delta(64); std::vector<u16> gcur_volume_delta(64);
std::vector<u16> gaudioFormat(64); // PBAudioAddr audio_addr (incl looping)
std::vector<u16> glooping(64); std::vector<u16> gaudioFormat(64);
std::vector<u16> gsrc_type(64); std::vector<u16> glooping(64);
std::vector<u16> gis_stream(64);
// loop
std::vector<u16> gloop1(64); std::vector<u16> gloop1(64);
std::vector<u16> gloop2(64); std::vector<u16> gloop2(64);
std::vector<u16> gloop3(64); std::vector<u16> gloop3(64);
// PBADPCMInfo adpcm
std::vector<u16> gadloop1(64); std::vector<u16> gadloop1(64);
std::vector<u16> gadloop2(64); std::vector<u16> gadloop2(64);
std::vector<u16> gadloop3(64); std::vector<u16> gadloop3(64);
@ -95,15 +120,14 @@ std::vector<u16> gis_stream(64);
std::vector<u16> gupdates4(64); std::vector<u16> gupdates4(64);
std::vector<u16> gupdates5(64); std::vector<u16> gupdates5(64);
std::vector<u32> gupdates_addr(64); std::vector<u32> gupdates_addr(64);
std::vector<u32> gupdates_data(64);
// Counters // Counters
int j = 0; int j = 0;
int k = 0; int k = 0;
long int l = 0; unsigned int l = 0;
int iupd = 0; int iupd = 0;
bool iupdonce = false; bool iupdonce = false;
std::vector<u16> viupd(15); // the length of the update frequency bar std::vector<u16> viupd(15); // the length of the update frequency bar
@ -127,6 +151,112 @@ extern CDebugger* m_frame;
// =======================================================================================
// Write title
// --------------
std::string writeTitle(int a)
{
std::string b;
if(a == 0)
{
b = " adpcm adpcm_loop\n";
b = b + " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n";
}
else if(a == 1)
{
b = " Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5\n";
}
else if(a == 2)
{
b = " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n";
}
else if(a == 3)
{
b = " Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n";
}
return b;
}
// =======================================================================================
// =======================================================================================
// Write main message (presets)
// --------------
std::string writeMessage(int a, int i)
{
char buf [1000] = "";
std::string sbuf;
// =======================================================================================
// PRESETS
// ---------------------------------------------------------------------------------------
/*
PRESET 0
" Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo]\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0 0 | 000 00000 00000 000 00000 00000 | 00000 00000[0 00000]
PRESET 1 (updates)
" Nr pos / end lpos | voll volr | src form coef | 1 2 3 4 5\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0 0 0 | 0 0 0 0 0
PRESET 2
" Nr pos / end lpos | voll volr | isl iss | e-l e-s\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0 0 | 000000 000000
*/
if(a == 0)
{
sprintf(buf,"%c%02i %08i/%08i %08i | %05i %05i | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i]",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i],
glooping[i], gis_stream[i],
gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i],
gfrac[i], gratio[i], gratiohi[i], gratiolo[i]
);
}
else if(a == 1)
{
sprintf(buf,"%c%02i %08i/%08i %08i | %05i %05i | %i %i %i | %i %i %i %i %i %08x %08x",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i],
gsrc_type[i], gaudioFormat[i], gcoef[i],
gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i], gupdates_addr[i], gupdates_data[i]
);
}
else if(a == 2)
{
sprintf(buf,"%c%02i %08i/%08i %08i | %05i %05i | %i %i | %06i %06i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i],
glooping[i], gis_stream[i],
gsampleEnd[i] - gloopPos[i], gsampleEnd[i] - gsamplePos[i]
);
}
/*
PRESET 3
" Nr voll volr dl dr curv delt mixc r | v1 v2 v3 v4 v5 v6 v7 | d1 d2 d3 d4 d5 d6 d7\n";
"---------------|00 00000 00000 00000 00000 00000 00000 00000 0 | 00000 00000 00000 00000 00000 00000 00000 | 00000 00000 00000 00000 00000 00000 00000
*/
else if(a == 3)
{
sprintf(buf,"%c%02i %05i %05i %05i %05i %05i %05i %05i %i | %05i %05i %05i %05i %05i %05i %05i | %05i %05i %05i %05i %05i %05i %05i",
223, i,
gvolume_left[i], gvolume_right[i], gmix_unknown[i], gmix_unknown2[i], gcur_volume[i], gcur_volume_delta[i],
gmixer_control[i], (gmixer_control[i] & MIXCONTROL_RAMPING),
gmixer_vol1[i], gmixer_vol2[i], gmixer_vol3[i], gmixer_vol4[i], gmixer_vol5[i],
gmixer_vol6[i], gmixer_vol7[i],
gmixer_d1[i], gmixer_d2[i], gmixer_d3[i], gmixer_d4[i], gmixer_d5[i],
gmixer_d6[i], gmixer_d7[i]
);
}
sbuf = buf;
return sbuf;
}
// =======================================================================================
// I placed this in CUCode_AX because it needs access to private members of that class. // I placed this in CUCode_AX because it needs access to private members of that class.
void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a) void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
{ {
@ -134,10 +264,138 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
AXParamBlock PBs[NUMBER_OF_PBS]; AXParamBlock PBs[NUMBER_OF_PBS];
int numberOfPBs = ReadOutPBs(PBs, NUMBER_OF_PBS); int numberOfPBs = ReadOutPBs(PBs, NUMBER_OF_PBS);
// Control how often the screen is updated // =======================================================================================
j++; // Update parameter values
l++; // --------------
// We could chose to update these only if a block is currently running - Later I'll add options
// to see both the current and the lastets active value.
//if (PBs[i].running)
int irun = 0;
for (int i = 0; i < numberOfPBs; i++)
{
if(PBs[i].running)
{
irun++;
}
// write a line if nothing is playing
if (i == numberOfPBs - 1 && irun == 0)
{
for (int i = 0; i < nFiles; i++)
{
std::string sfbuff;
sfbuff = "-----";
aprintf(i, (char *)sfbuff.c_str());
}
}
// ---------------------------------------------------------------------------------------
// Prepare conditions
// --------------
bool Conditions;
if (gOnlyLooping)
{
Conditions = PBs[i].audio_addr.looping;
}
else
{
Conditions = (numberRunning.at(i) > 0 || PBs[i].audio_addr.looping);
}
// --------------
if(Conditions)
{
// AXPB base
gcoef[i] = PBs[i].unknown1;
gloopPos[i] = (PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo;
gsampleEnd[i] = (PBs[i].audio_addr.end_addr_hi << 16) | PBs[i].audio_addr.end_addr_lo;
gsamplePos[i] = (PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo;
// PBSampleRateConverter src
gratio[i] = (u32)(((PBs[i].src.ratio_hi << 16) + PBs[i].src.ratio_lo) * ratioFactor);
gratiohi[i] = PBs[i].src.ratio_hi;
gratiolo[i] = PBs[i].src.ratio_lo;
gfrac[i] = PBs[i].src.cur_addr_frac;
// adpcm_loop_info
gadloop1[i] = PBs[i].adpcm.pred_scale;
gadloop2[i] = PBs[i].adpcm.yn1;
gadloop3[i] = PBs[i].adpcm.yn2;
gloop1[i] = PBs[i].adpcm_loop_info.pred_scale;
gloop2[i] = PBs[i].adpcm_loop_info.yn1;
gloop3[i] = PBs[i].adpcm_loop_info.yn2;
// updates
gupdates1[i] = PBs[i].updates.num_updates[0];
gupdates2[i] = PBs[i].updates.num_updates[1];
gupdates3[i] = PBs[i].updates.num_updates[2];
gupdates4[i] = PBs[i].updates.num_updates[3];
gupdates5[i] = PBs[i].updates.num_updates[4];
gupdates_addr[i] = (PBs[i].updates.data_hi << 16) | PBs[i].updates.data_lo;
gupdates_data[i] = Memory_Read_U32(gupdates_addr[i]);
gaudioFormat[i] = PBs[i].audio_addr.sample_format;
glooping[i] = PBs[i].audio_addr.looping;
gsrc_type[i] = PBs[i].src_type;
gis_stream[i] = PBs[i].is_stream;
// mixer
gvolume_left[i] = PBs[i].mixer.volume_left;
gvolume_right[i] = PBs[i].mixer.volume_right;
gmix_unknown[i] = PBs[i].mixer.unknown;
gmix_unknown2[i] = PBs[i].mixer.unknown2;
gmixer_control[i] = PBs[i].mixer_control;
gcur_volume[i] = PBs[i].vol_env.cur_volume;
gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta;
gmixer_vol1[i] = PBs[i].mixer.unknown3[0];
gmixer_vol2[i] = PBs[i].mixer.unknown3[2];
gmixer_vol3[i] = PBs[i].mixer.unknown3[4];
gmixer_vol4[i] = PBs[i].mixer.unknown3[6];
gmixer_vol5[i] = PBs[i].mixer.unknown3[0];
gmixer_vol6[i] = PBs[i].mixer.unknown3[2];
gmixer_vol7[i] = PBs[i].mixer.unknown3[4];
gmixer_d1[i] = PBs[i].mixer.unknown4[1];
gmixer_d2[i] = PBs[i].mixer.unknown4[3];
gmixer_d3[i] = PBs[i].mixer.unknown4[5];
gmixer_d4[i] = PBs[i].mixer.unknown4[7];
gmixer_d5[i] = PBs[i].mixer.unknown4[1];
gmixer_d6[i] = PBs[i].mixer.unknown4[3];
gmixer_d7[i] = PBs[i].mixer.unknown4[5];
// ---------------------------------------------------------------------------------------
// Write to file
// --------------
for (int ii = 0; ii < nFiles; ii++)
{
std::string sfbuff;
if(a == 0) sfbuff = "***"; // note if it's before or after an update
else sfbuff = " ";
sfbuff = sfbuff + writeMessage(ii, i);
sfbuff = sfbuff + "\n";
aprintf(ii, (char *)sfbuff.c_str());
}
// --------------
}
}
// ==============
// =======================================================================================
// Control how often the screen is updated, and then update the screen
// --------------
if(a == 0) j++;
//if(l == pow((double)2,32)) l=0; // reset l
//l++;
if (j > (200/gUpdFreq)) if (j > (200/gUpdFreq))
{ {
@ -156,11 +414,9 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
{ {
vector1.at(i).at(j-1) = vector1.at(i).at(j); vector1.at(i).at(j-1) = vector1.at(i).at(j);
} }
} }
// Save the latest value
// Save the latest value
for (int i = 0; i < numberOfPBs; i++) for (int i = 0; i < numberOfPBs; i++)
{ {
vector1.at(i).at(vectorLength-1) = PBs[i].running ? true : false; vector1.at(i).at(vectorLength-1) = PBs[i].running ? true : false;
@ -183,11 +439,9 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
{ {
vector2.at(i).at(j-1) = vector2.at(i).at(j); vector2.at(i).at(j-1) = vector2.at(i).at(j);
} }
} }
// Save the latest value
// Save the latest value
for (int i = 0; i < numberOfPBs; i++) for (int i = 0; i < numberOfPBs; i++)
{ {
vector2.at(i).at(vectorLength2-1) = PBs[i].running; vector2.at(i).at(vectorLength2-1) = PBs[i].running;
@ -218,34 +472,16 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
// -------------- // --------------
char buffer [1000] = ""; char buffer [1000] = "";
std::string sbuff; std::string sbuff;
if(gPreset == 0) sbuff = writeTitle(gPreset);
{
sbuff = sbuff + " adpcm adpcm_loop\n";
sbuff = sbuff + " Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo] | 1 2 3 4 5\n";
}
else if(gPreset == 1)
{
sbuff = sbuff + " Nr pos / end lpos | voll volr curv vold | src coef mixc\n";
}
else if(gPreset == 2)
{
sbuff = sbuff + " Nr pos / end lpos | voll volr | isl iss | e-l e-s\n";
}
// ============== // ==============
// go through all running blocks // go through all running blocks
for (int i = 0; i < numberOfPBs; i++) for (int i = 0; i < numberOfPBs; i++)
{ {
// ======================================================================================= // ---------------------------------------------------------------------------------------
// Prepare conditions // Prepare conditions. TODO: We use this in two places now, make it only one
// -------------- // --------------
bool Conditions; bool Conditions;
if (gOnlyLooping) if (gOnlyLooping)
@ -256,8 +492,10 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
{ {
Conditions = (numberRunning.at(i) > 0 || PBs[i].audio_addr.looping); Conditions = (numberRunning.at(i) > 0 || PBs[i].audio_addr.looping);
} }
// ============== // --------------
// use the condition
if (Conditions) if (Conditions)
{ {
@ -309,59 +547,6 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
// --------- // ---------
// We could chose to update these only if a block is currently running - Later I'll add options
// to see both the current and the lastets active value.
//if (PBs[i].running)
if (true)
{
// AXPB base
gcoef[i] = PBs[i].unknown1;
gloopPos[i] = (PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo;
gsampleEnd[i] = (PBs[i].audio_addr.end_addr_hi << 16) | PBs[i].audio_addr.end_addr_lo;
gsamplePos[i] = (PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo;
// PBSampleRateConverter src
gratio[i] = (u32)(((PBs[i].src.ratio_hi << 16) + PBs[i].src.ratio_lo) * ratioFactor);
gratiohi[i] = PBs[i].src.ratio_hi;
gratiolo[i] = PBs[i].src.ratio_lo;
gfrac[i] = PBs[i].src.cur_addr_frac;
// adpcm_loop_info
gadloop1[i] = PBs[i].adpcm.pred_scale;
gadloop2[i] = PBs[i].adpcm.yn1;
gadloop3[i] = PBs[i].adpcm.yn2;
gloop1[i] = PBs[i].adpcm_loop_info.pred_scale;
gloop2[i] = PBs[i].adpcm_loop_info.yn1;
gloop3[i] = PBs[i].adpcm_loop_info.yn2;
// updates
gupdates1[i] = PBs[i].updates.num_updates[0];
gupdates2[i] = PBs[i].updates.num_updates[1];
gupdates3[i] = PBs[i].updates.num_updates[2];
gupdates4[i] = PBs[i].updates.num_updates[3];
gupdates5[i] = PBs[i].updates.num_updates[4];
gupdates_addr[i] = (PBs[i].updates.data_hi << 16) | PBs[i].updates.data_lo;
gaudioFormat[i] = PBs[i].audio_addr.sample_format;
glooping[i] = PBs[i].audio_addr.looping;
gsrc_type[i] = PBs[i].src_type;
gis_stream[i] = PBs[i].is_stream;
// mixer
gvolume_left[i] = PBs[i].mixer.volume_left;
gvolume_right[i] = PBs[i].mixer.volume_right;
gmixer_control[i] = PBs[i].mixer_control;
gcur_volume[i] = PBs[i].vol_env.cur_volume;
gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta;
}
// hopefully this is false if we don't have a debugging window and so it doesn't cause a crash // hopefully this is false if we don't have a debugging window and so it doesn't cause a crash
if(m_frame) if(m_frame)
{ {
@ -396,54 +581,8 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
m_frame->m_GPRListView->m_CachedRegs[22][i] = gupdates5[i]; m_frame->m_GPRListView->m_CachedRegs[22][i] = gupdates5[i];
} }
// =======================================================================================
// PRESETS
// ---------------------------------------------------------------------------------------
/*
PRESET 0
" Nr pos / end lpos | voll volr | isl iss | pre yn1 yn2 pre yn1 yn2 | frac ratio[hi lo] | 1 2 3 4 5\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0 0 | 000 00000 00000 000 00000 00000 | 00000 00000[0 00000] |
PRESET 1
" Nr pos / end lpos | voll volr curv vold | src coef mixc\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 00000 00000 | 0 0 0
PRESET 2
" Nr pos / end lpos | voll volr | isl iss | e-l e-s\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0 0 | 000000 000000
*/
if(gPreset == 0)
{
sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i | %i %i | %03i %05i %05i %03i %05i %05i | %05i %05i[%i %05i] | %i %i %i %i %i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i],
glooping[i], gis_stream[i],
gadloop1[i], gadloop2[i], gadloop3[i], gloop1[i], gloop2[i], gloop3[i],
gfrac[i], gratio[i], gratiohi[i], gratiolo[i],
gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i]
);
}
else if(gPreset == 1)
{
sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i %05i %05i | %i %i %i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i], gcur_volume[i], gcur_volume_delta[i],
gsrc_type[i], gcoef[i], gmixer_control[i]
);
}
else if(gPreset == 2)
{
sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i | %i %i | %06i %06i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i],
glooping[i], gis_stream[i],
gsampleEnd[i] - gloopPos[i], gsampleEnd[i] - gsamplePos[i]
);
}
// add new line // add new line
sbuff = sbuff + buffer; strcpy(buffer, ""); sbuff = sbuff + writeMessage(gPreset, i); strcpy(buffer, "");
sbuff = sbuff + "\n"; sbuff = sbuff + "\n";
@ -522,29 +661,25 @@ void CUCode_AX::Logging(short* _pBuffer, int _iSize, int a)
// ======================================================================================= // =======================================================================================
// Print // Print
// --------------------------------------------------------------------------------------- // ----------------
ClearScreen(); ClearScreen();
// we'll always have one to many \n at the end, remove it
//wprintf("%s", sbuff.substr(0, sbuff.length()-1).c_str());
wprintf("%s", sbuff.c_str()); wprintf("%s", sbuff.c_str());
sbuff.clear(); strcpy(buffer, ""); sbuff.clear(); strcpy(buffer, "");
// ================
// New values are written so update - DISABLED - It flickered a lot, even worse than a // New values are written so update - DISABLED - It flickered a lot, even worse than a
// console window. I'll add a console window later to show the current status. // console window. So for now only the console windows is updated.
//if(m_frame) /*
if(false) if(m_frame)
{ {
//m_frame->NotifyUpdate(); m_frame->NotifyUpdate();
} }
*/
k=0; k=0;
j=0; j=0;
} // end of if (j>20) } // end of if (j>20)
} // end of function } // end of function

View File

@ -128,6 +128,31 @@ void ADPCM_Loop(AXParamBlock& pb)
//else stream and we should not attempt to replace values //else stream and we should not attempt to replace values
} }
// =======================================================================================
// Volume control (ramping)
// --------------
u16 ADPCM_Vol(u16 vol, u16 delta, u16 mixer_control)
{
int x = vol;
if (delta && delta < 0x4000)
x += delta; // unsure what the right step is
//x ++;
//x += 8; //?
else if (delta && delta > 0x4000)
//x -= (0x8000 - pb.mixer.unknown); // this didn't work
x--;
if (x < 0) x = 0; // make limits
// does this make any sense?
//if (pb.mixer_control < 1000 && x < pb.mixer_control) x = pb.mixer_control;
//if (x >= 0x7fff) xl = 0x7fff; // this seems to high
if (mixer_control > 1000 && x > mixer_control) x = mixer_control;
return x; // update volume
}
// ==============
void CUCode_AX::MixAdd(short* _pBuffer, int _iSize) void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
{ {
AXParamBlock PBs[NUMBER_OF_PBS]; AXParamBlock PBs[NUMBER_OF_PBS];
@ -156,18 +181,22 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
{ {
AXParamBlock& pb = PBs[i]; AXParamBlock& pb = PBs[i];
// get necessary values
const u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
const u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
const u32 updaddr = (u32)(pb.updates.data_hi << 16) | pb.updates.data_lo;
const u32 upddata = Memory_Read_U32(updaddr);
// ======================================================================================= // =======================================================================================
/* /*
Fix problems introduced with the SSBM fix - Sometimes when a music stream ended sampleEnd Fix problems introduced with the SSBM fix - Sometimes when a music stream ended sampleEnd
would become extremely high and the game would play random sound data from ARAM resulting in would become extremely high and the game would play random sound data from ARAM resulting in
a strange noise. This should take care of that. - Some games (Monkey Ball 1 and Tales of a strange noise. This should take care of that. - Some games (Monkey Ball 1 and Tales of
Symphonia) also had one odd block with a strange high loopPos and strange num_updates values, Symphonia and other) also had one odd last block with a strange high loopPos and strange
the loopPos limit turns those off also. - Please report any side effects. num_updates values, the loopPos limit turns those off also. - Please report any side effects.
*/ */
// ------------ // ------------
const u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
const u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
if ( if (
(sampleEnd > 0x10000000 || loopPos > 0x10000000) (sampleEnd > 0x10000000 || loopPos > 0x10000000)
&& gSSBMremedy1 && gSSBMremedy1
@ -191,38 +220,38 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
/* /*
// the fact that no settings are reset (except running) after a SSBM type music stream or another // the fact that no settings are reset (except running) after a SSBM type music stream or another
looping block (for example in Battle Stadium DON) has ended could cause loud garbled sound to be looping block (for example in Battle Stadium DON) has ended could cause loud garbled sound to be
played from one or more blocks. Battle Stadium DON would usually have as much as five short looping played from one or more blocks. Perhaps it was in conjunction with the old sequenced music fix below,
sounds (for example for running water and other things), but one or more of those would turn in to I'm not sure. This was an attempt to prevent that anyway by resetting all. But I'm not sure if this
looping noise machines if the old SSBM fix (withouth the pb.mixer_control check) was applied. This is needed anymore. Please try to play SSBM without it and see if it works anyway.
would fix that by resetting the values after a looping block had ended. But it would be at the price
of turing off all looping sounds except the music streams, it seemed. But hopefully with the improved
SSBM music fix this check is not needed. I'll save it for now but it may perhaps be deleted in the
future.
*/ */
if ( if (
// detect blocks that have recently been running that we should reset // detect blocks that have recently been running that we should reset
pb.running == 0 && pb.audio_addr.looping == 1 pb.running == 0 && pb.audio_addr.looping == 1
//pb.running == 0 && pb.adpcm_loop_info.pred_scale
// this prevents us from ruining sequenced music blocks // this prevents us from ruining sequenced music blocks, may not be needed
/*
&& !(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2] && !(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2]
|| pb.updates.num_updates[3] || pb.updates.num_updates[4]) || pb.updates.num_updates[3] || pb.updates.num_updates[4])
*/
&& !upddata
&& pb.mixer_control == 0 // only use this in SSBM && pb.mixer_control == 0 // only use this in SSBM
&& gSSBMremedy2 // let us turn this fix on and off && gSSBMremedy2 // let us turn this fix on and off
) )
{ {
// reset all values, or mostly all // reset the detection values
pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0;
pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0;
pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0;
pb.src.cur_addr_frac = 0; PBs[i].src.ratio_hi = 0; PBs[i].src.ratio_lo = 0;
pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0;
pb.audio_addr.looping = 0; pb.audio_addr.looping = 0;
pb.adpcm_loop_info.pred_scale = 0; pb.adpcm_loop_info.pred_scale = 0;
pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0;
//pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0;
//pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0;
//pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0;
//pb.src.cur_addr_frac = 0; PBs[i].src.ratio_hi = 0; PBs[i].src.ratio_lo = 0;
//pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0;
} }
// ============= // =============
@ -233,17 +262,26 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
Sequenced music fix - Because SSBM type music and other (for example Battle Stadium DON) looping Sequenced music fix - Because SSBM type music and other (for example Battle Stadium DON) looping
blocks did no have its pred_scale (or any other parameter except running) turned off after a song blocks did no have its pred_scale (or any other parameter except running) turned off after a song
was stopped a pred_scale check here had the effect of turning those blocks on immediately after was stopped a pred_scale check here had the effect of turning those blocks on immediately after
the stopped. Because the pred_scale check caused these effects I'm trying the num_updates check the stopped. One way to easily test this is to start a game in BS DON, wait for the Fight message
instead. Please report any side effects. so that the loops begin, and then exit the game and you can see that the sound effects will
continue to play in the menus. That's not good. Because the pred_scale check caused these effects
I'm trying an update data check instead, it relieas on the assumption that all games that don't
use sequencing have blank memory at the update address so that upddata = 0 in those cases. That
turned out to now hold, many games that don't use sequencing still had update_addr pointing to
some memory location with data, either inside the parameter block space or close before or after
it.
*/ */
// ------------ // ------------
//if (!pb.running && pb.adpcm_loop_info.pred_scale) //if (!pb.running && pb.adpcm_loop_info.pred_scale)
/**/ //if (!pb.running && pb.audio_addr.looping)
if (!pb.running && upddata)
/*
if (!pb.running && if (!pb.running &&
(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2] (pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2]
|| pb.updates.num_updates[3] || pb.updates.num_updates[4]) || pb.updates.num_updates[3] || pb.updates.num_updates[4])
&& gSequenced && gSequenced
) )
*/
{ {
pb.running = 1; pb.running = 1;
} }
@ -325,22 +363,6 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
// ============== // ==============
// =======================================================================================
// Streaming music and volume - The streaming music in Paper Mario use these settings:
// Base settings
// is_stream = 1
// src_type = 0
// PBAudioAddr
// audio_addr.looping = 1 (adpcm_loop_info.pred_scale = value, .yn1 = 0, .yn2 = 0)
/*
However. Some of the ingame music and seemingly randomly some other music incorrectly get
volume = 0 for both left and right. This also affects Fire Emblem. But Starfox Assault
that also use is_stream = 1 has no problem wuth the volume, but its settings are somewhat
different, it uses src_type = 1 and pb.src.ratio_lo (fraction) != 0
*/
// ==============
// ======================================================================================= // =======================================================================================
// Walk through _iSize // Walk through _iSize
for (int s = 0; s < _iSize; s++) for (int s = 0; s < _iSize; s++)
@ -402,10 +424,18 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
if (pb.mixer_control & MIXCONTROL_RAMPING) if (pb.mixer_control & MIXCONTROL_RAMPING)
{ {
int x = pb.vol_env.cur_volume; int x = pb.vol_env.cur_volume;
x += pb.vol_env.cur_volume_delta; x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
// that use this?
if (x < 0) x = 0; if (x < 0) x = 0;
if (x >= 0x7fff) x = 0x7fff; if (x >= 0x7fff) x = 0x7fff;
pb.vol_env.cur_volume = x; // maybe not per sample?? :P pb.vol_env.cur_volume = x; // maybe not per sample?? :P
// strange way to not use this in Skies where it didn't work well
if(pb.mixer_control != 9 && pb.mixer_control != 123)
{
pb.mixer.volume_left = ADPCM_Vol(pb.mixer.volume_left, pb.mixer.unknown, pb.mixer_control);
pb.mixer.volume_right = ADPCM_Vol(pb.mixer.volume_right, pb.mixer.unknown2, pb.mixer_control);
}
} }
int leftmix = pb.mixer.volume_left >> 5; int leftmix = pb.mixer.volume_left >> 5;
@ -459,6 +489,12 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
// write back out pbs // write back out pbs
WriteBackPBs(PBs, numberOfPBs); WriteBackPBs(PBs, numberOfPBs);
// write logging data to debugger again after the update
if(m_frame)
{
CUCode_AX::Logging(_pBuffer, _iSize, 1);
}
} }
void CUCode_AX::Update() void CUCode_AX::Update()
@ -708,7 +744,7 @@ int CUCode_AX::ReadOutPBs(AXParamBlock* _pPBs, int _num)
break; break;
} }
// return the number of readed PBs // return the number of read PBs
return count; return count;
} }

View File

@ -61,14 +61,19 @@ std::vector<u32> gsamplePos(64);
std::vector<u32> gratiolo(64); std::vector<u32> gratiolo(64);
std::vector<u32> gfrac(64); std::vector<u32> gfrac(64);
std::vector<u32> gcoef(64); std::vector<u32> gcoef(64);
// PBSampleRateConverter mixer // PBSampleRateConverter mixer
std::vector<u16> gvolume_left(64); std::vector<u16> gvolume_left(64);
std::vector<u16> gvolume_right(64); std::vector<u16> gvolume_right(64);
std::vector<u16> gmixer_control(64);
std::vector<u16> gcur_volume(64);
std::vector<u16> gcur_volume_delta(64);
std::vector<u16> gaudioFormat(64);
std::vector<u16> glooping(64); std::vector<u16> gaudioFormat(64);
std::vector<u16> gsrc_type(64); std::vector<u16> glooping(64);
std::vector<u16> gis_stream(64); std::vector<u16> gsrc_type(64);
std::vector<u16> gis_stream(64);
// loop // loop
std::vector<u16> gloop1(64); std::vector<u16> gloop1(64);
@ -175,7 +180,7 @@ void Logging()
char buffer [1000] = ""; char buffer [1000] = "";
std::string sbuff; std::string sbuff;
//sbuff = sbuff + " Nr | | frac ratio | old new \n"; // 5 //sbuff = sbuff + " Nr | | frac ratio | old new \n"; // 5
sbuff = sbuff + " Nr pos / end lpos | voll volr | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n"; sbuff = sbuff + " Nr pos / end lpos | voll volr curv vold mix | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n";
// -------------- // --------------
@ -254,6 +259,10 @@ void Logging()
// mixer // mixer
gvolume_left[i] = PBs[i].mixer.volume_left; gvolume_left[i] = PBs[i].mixer.volume_left;
gvolume_right[i] = PBs[i].mixer.volume_right; gvolume_right[i] = PBs[i].mixer.volume_right;
gmixer_control[i] = PBs[i].mixer_control;
gcur_volume[i] = PBs[i].vol_env.cur_volume;
gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta;
// other stuff // other stuff
Jump[i] = (gfrac[i] >> 16); // This is 1 or 0 Jump[i] = (gfrac[i] >> 16); // This is 1 or 0
@ -268,12 +277,12 @@ void Logging()
// PRESETS // PRESETS
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
/* /*
/" Nr pos / end lpos | voll volr | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n"; /" Nr pos / end lpos | voll volr curv vold mix | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 | 0[000 00000 00000] 0 | 00000 00000[0 00000] | "---------------|00 12341234/12341234 12341234 | 00000 00000 00000 0000 00000 | 0[000 00000 00000] 0 | 00000 00000[0 00000] |
*/ */
sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i | %i[%03i %05i %05i] %i | %05i %05i[%i %05i] | %i %i %i %i %i", sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i %05i %04i %05i | %i[%03i %05i %05i] %i | %05i %05i[%i %05i] | %i %i %i %i %i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i], 223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i], gvolume_left[i], gvolume_right[i], gcur_volume[i], gcur_volume_delta[i], gmixer_control[i],
glooping[i], gloop1[i], gloop2[i], gloop3[i], gis_stream[i], glooping[i], gloop1[i], gloop2[i], gloop3[i], gis_stream[i],
gfrac[i], gratio[i], gratiohi[i], gratiolo[i], gfrac[i], gratio[i], gratiohi[i], gratiolo[i],
gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i] gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i]