diff --git a/Externals/MusicMod/Common/Common.vcproj b/Externals/MusicMod/Common/Common.vcproj
new file mode 100644
index 0000000000..bfd7927ca2
--- /dev/null
+++ b/Externals/MusicMod/Common/Common.vcproj
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Externals/MusicMod/Data/win32/Plainamp.ini b/Externals/MusicMod/Data/win32/Plainamp.ini
new file mode 100644
index 0000000000..d82f44952a
--- /dev/null
+++ b/Externals/MusicMod/Data/win32/Plainamp.ini
@@ -0,0 +1,40 @@
+[Plainamp]
+OutputPluginActive___out_ds.dll=1
+Volume=255
+Loop=1
+WinPlaceConsole=(1,(62,441,1179,845))
+WinPlaceMain=(1,(274,203,1005,765))
+MinimizeToTray=1
+Panning=0
+CurPresetFixed=-1
+PreventDistortion=1
+Order=3
+PlaylistFollow=1
+PlaylistEntryNumberZeroPadding=1
+CurPlaylistPosition=0
+InfinitePlaylist=0
+ManagerGrid=1
+WinPlaceManager=(1,(500,400,1000,700))
+OrderBand=(0,-2,0,1)
+EqBand=(1,-2,0,1)
+SeekBand=(2,-2,0,1)
+VolBand=(3,-2,0,1)
+PanBand=(4,-2,0,1)
+ButtonsBand=(5,134,0,1)
+VisBand=(6,134,0,1)
+InvertPanSlider=0
+CurDir=C:\
+WarnPluginsMissing=1
+[out_wave_gpl]
+config=14000000002400000100000000000000FFFFFFFF0100000036
+[out_ds]
+cfg_hw_mix=1
+cfg_buf_ms=2000
+cfg_trackhack=0
+cfg_prebuf2=500
+cfg_fade_seek.on=0
+cfg_fade_pause.on=0
+cfg_fadevol=0
+cfg_wait=0
+[Interface]
+ShowConsole = False
diff --git a/Externals/MusicMod/Data/win32/PluginsMusic/in_vgmstream.dll b/Externals/MusicMod/Data/win32/PluginsMusic/in_vgmstream.dll
new file mode 100644
index 0000000000..f54a9f9e62
Binary files /dev/null and b/Externals/MusicMod/Data/win32/PluginsMusic/in_vgmstream.dll differ
diff --git a/Externals/MusicMod/Data/win32/PluginsMusic/out_ds.dll b/Externals/MusicMod/Data/win32/PluginsMusic/out_ds.dll
new file mode 100644
index 0000000000..501049b1f7
Binary files /dev/null and b/Externals/MusicMod/Data/win32/PluginsMusic/out_ds.dll differ
diff --git a/Externals/MusicMod/Data/win32/PluginsMusic/out_wave_gpl.dll b/Externals/MusicMod/Data/win32/PluginsMusic/out_wave_gpl.dll
new file mode 100644
index 0000000000..1f2c9f3b4f
Binary files /dev/null and b/Externals/MusicMod/Data/win32/PluginsMusic/out_wave_gpl.dll differ
diff --git a/Externals/MusicMod/Data/x64/Plainamp.ini b/Externals/MusicMod/Data/x64/Plainamp.ini
new file mode 100644
index 0000000000..b1a908bd6d
--- /dev/null
+++ b/Externals/MusicMod/Data/x64/Plainamp.ini
@@ -0,0 +1,29 @@
+[Plainamp]
+OutputPluginActive___out_wave_gpl.dll=1
+Volume=100
+Loop=1
+WinPlaceConsole=(1,(62,441,1179,845))
+WinPlaceMain=(1,(274,203,1005,765))
+MinimizeToTray=1
+Panning=0
+CurPresetFixed=-1
+PreventDistortion=1
+Order=3
+PlaylistFollow=1
+PlaylistEntryNumberZeroPadding=1
+CurPlaylistPosition=0
+InfinitePlaylist=1
+ManagerGrid=1
+WinPlaceManager=(1,(500,400,1000,700))
+OrderBand=(0,-2,0,1)
+EqBand=(1,-2,0,1)
+SeekBand=(2,-2,0,1)
+VolBand=(3,-2,0,1)
+PanBand=(4,-2,0,1)
+ButtonsBand=(5,134,0,1)
+VisBand=(6,134,0,1)
+InvertPanSlider=0
+CurDir=C:\
+WarnPluginsMissing=1
+[out_wave_gpl]
+config=14000000002400000100000000000000FFFFFFFF0100000036
diff --git a/Externals/MusicMod/Data/x64/PluginsMusic/in_vgmstream.dll b/Externals/MusicMod/Data/x64/PluginsMusic/in_vgmstream.dll
new file mode 100644
index 0000000000..bf2af34f79
Binary files /dev/null and b/Externals/MusicMod/Data/x64/PluginsMusic/in_vgmstream.dll differ
diff --git a/Externals/MusicMod/Data/x64/PluginsMusic/out_wave_gpl.dll b/Externals/MusicMod/Data/x64/PluginsMusic/out_wave_gpl.dll
new file mode 100644
index 0000000000..da0ccab700
Binary files /dev/null and b/Externals/MusicMod/Data/x64/PluginsMusic/out_wave_gpl.dll differ
diff --git a/Externals/MusicMod/Main/Main.vcproj b/Externals/MusicMod/Main/Main.vcproj
new file mode 100644
index 0000000000..2f6abdff78
--- /dev/null
+++ b/Externals/MusicMod/Main/Main.vcproj
@@ -0,0 +1,417 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Externals/MusicMod/Main/Src/Frame.cpp b/Externals/MusicMod/Main/Src/Frame.cpp
new file mode 100644
index 0000000000..a29d02c1ed
--- /dev/null
+++ b/Externals/MusicMod/Main/Src/Frame.cpp
@@ -0,0 +1,466 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Include
+// ŻŻŻŻŻŻŻŻŻŻ
+#include // System
+
+#include "Core.h" // Core
+
+#include "IniFile.h" // Common
+#include "Log.h"
+
+#include "../../../../Source/Core/DolphinWX/Src/Globals.h" // DolphinWX
+#include "../../../../Source/Core/DolphinWX/Src/Frame.h"
+
+#include "../../../../Source/Core/DolphinWX/resources/toolbar_plugin_dsp.c" // Icons
+#include "../../../../Source/Core/DolphinWX/resources/Boomy.h"
+#include "../../../../Source/Core/DolphinWX/resources/Vista.h"
+#include "../../../../Source/Core/DolphinWX/resources/KDE.h"
+#include "../../../../Source/Core/DolphinWX/resources/X-Plastik.h"
+
+#include "../../Player/Src/PlayerExport.h" // Player
+//////////////////////////////////
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations and definitions
+// ŻŻŻŻŻŻŻŻŻŻ
+namespace MusicMod
+{
+ bool GlobalMute = false;
+ bool GlobalPause = false;
+ bool bShowConsole = false;
+ int GlobalVolume = 125;
+ extern bool dllloaded;
+
+ void ShowConsole();
+ void Init();
+}
+//////////////////////////////////
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Change the brightness of a wxBitmap
+// ŻŻŻŻŻŻŻŻŻŻ
+wxBitmap SetBrightness(wxBitmap _Bitmap, int _Brightness, bool Gray)
+{
+ wxImage _Image = _Bitmap.ConvertToImage();
+ wxImage _Image2 = _Bitmap.ConvertToImage();
+
+ wxString Tmp;
+
+ if(_Brightness < 0) _Brightness = 0; // Limits
+ if(_Brightness > 255) _Brightness = 255;
+
+ _Brightness = 255 - _Brightness; // Make big values brighter
+
+ // Remove the alpha layer first
+ for(int y = 0; y < _Bitmap.GetWidth(); y++)
+ {
+ for(int x = 0; x < _Bitmap.GetHeight(); x++)
+ _Image.SetAlpha(x, y, 255);
+ }
+
+ for(int y = 0; y < _Bitmap.GetWidth(); y++)
+ {
+ //Tmp += wxString::Format("\n %i: ", y);
+
+ for(int x = 0; x < _Bitmap.GetHeight(); x++)
+ {
+ u8 R = _Image.GetRed(x, y); // Get colors
+ u8 G = _Image.GetGreen(x, y);
+ u8 B = _Image.GetBlue(x, y);
+
+ //if((x == 5 | x == 6) && y == 15) Tmp += wxString::Format("%03i %03i %03i", R, G, B);
+
+ if(_Brightness > 128)
+ {
+ int Bright = _Brightness - 128;
+ R = R - Bright * (R - 0) / 128;
+ G = G - Bright * (G - 0) / 128;
+ B = B - Bright * (B - 0) / 128;
+
+ // 118 - 72 * 118 / 128 = 118 - 66.3 = 52
+ // 119 - = 119 - 66.9 = 52
+ }
+ else
+ {
+ int Bright = 128 - _Brightness;
+ R = R - Bright * (R - 255) / 128;
+ G = G - Bright * (G - 255) / 128;
+ B = B - Bright * (B - 255) / 128;
+ }
+
+ //if((x == 5 | x == 6) && y == 15) Tmp += wxString::Format(" %03i %03i %03i | ", R, G, B);
+
+ _Image.SetRGB(x, y, R, G, B);
+ }
+ }
+ // Return the alpha
+ _Image.SetAlpha(_Image2.GetAlpha(), true);
+
+ // Update the bitmap
+ if(Gray)
+ return wxBitmap(_Image.ConvertToGreyscale());
+ else
+ return wxBitmap(_Image);
+
+ //wxMessageBox(Tmp);
+}
+//////////////////////////////////
+
+
+#ifdef MUSICMOD
+void
+CFrame::MM_InitBitmaps(int Theme)
+{
+ // Define the log bitmaps
+ switch (Theme)
+ {
+ case BOOMY:
+ m_Bitmaps[Toolbar_Log] = wxGetBitmapFromMemory(Toolbar_Log_png);
+ break;
+ case VISTA:
+ m_Bitmaps[Toolbar_Log] = wxGetBitmapFromMemory(Toolbar_Log1_png);
+ break;
+ case XPLASTIK:
+ m_Bitmaps[Toolbar_Log] = wxGetBitmapFromMemory(Toolbar_Log2_png);
+ break;
+ case KDE:
+ m_Bitmaps[Toolbar_Log] = wxGetBitmapFromMemory(Toolbar_Log3_png);
+ break;
+ default: PanicAlert("Theme selection went wrong");
+ }
+
+ // Create a gray version
+ m_Bitmaps[Toolbar_PluginDSP_Dis] = wxBitmap(SetBrightness(m_Bitmaps[Toolbar_PluginDSP], 165, true));
+ m_Bitmaps[Toolbar_Log_Dis] = wxBitmap(SetBrightness(m_Bitmaps[Toolbar_Log], 165, true));
+
+ // Update in case the bitmap has been updated
+ //if (GetToolBar() != NULL) TheToolBar->FindById(Toolbar_Log)->SetNormalBitmap(m_Bitmaps[Toolbar_Log]);
+}
+
+
+void
+CFrame::MM_PopulateGUI()
+{
+ wxToolBar* toolBar = TheToolBar; // Shortcut
+
+ toolBar->AddSeparator();
+
+ MusicMod::Init();
+
+ // ---------------------------------------
+ // Draw a rotated music label
+ // ---------------------
+ wxBitmap m_RotatedText(30, 15);
+ wxMemoryDC dc;
+ dc.SelectObject(m_RotatedText);
+ wxBrush BackgroundGrayBrush(_T("#ece9d8")); // The right color in windows
+
+ // Set outline and fill colors
+ dc.SetBackground(BackgroundGrayBrush);
+ dc.Clear();
+
+ wxFont m_font(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
+ dc.SetFont(m_font);
+ dc.SetTextForeground(wxColour(*wxLIGHT_GREY));
+
+ dc.DrawText(wxT("Music"), 0, 0);
+ m_RotatedText = wxBitmap(m_RotatedText.ConvertToImage().Rotate90(false));
+
+ wxStaticBitmap * m_StaticBitmap = new wxStaticBitmap(toolBar, wxID_ANY, m_RotatedText);
+
+ toolBar->AddControl(m_StaticBitmap);
+ // ---------------------------
+
+
+
+ mm_ToolMute = toolBar->AddTool(IDM_MUTE, _T("Mute"), m_Bitmaps[Toolbar_PluginDSP], _T("Mute music"));
+ mm_ToolPlay = toolBar->AddTool(IDM_MUSIC_PLAY, _T("Play"), m_Bitmaps[Toolbar_Play], _T("Play or pause music without pausing the game"));
+
+ // This cause the disabled tool bitmap to become some kind of monochrome version
+ /*
+ mm_ToolMute = new wxToolBarToolBase(toolBar, IDM_MUTE, _T("Mute"), m_Bitmaps[Toolbar_PluginDSP],
+ m_Bitmaps[Toolbar_PluginDSP], wxITEM_CHECK, 0, _T("Mute music"));
+ toolBar->AddTool(mm_ToolMute);
+
+ mm_ToolPlay = new wxToolBarToolBase(toolBar, IDM_MUSIC_PLAY, _T("Play"), m_Bitmaps[Toolbar_Play],
+ m_Bitmaps[Toolbar_Play], wxITEM_NORMAL, 0, _T("Play or pause music without pausing the game"));
+ toolBar->AddTool(mm_ToolPlay);
+ */
+
+
+ // ---------------------
+ /* Lots of code to get a label for the slider, in 2.9.0 AddControl accepts a label so then
+ this code can be simplified a lot */
+ // ---------
+ wxPanel * mm_SliderPanel = new wxPanel(toolBar, IDS_VOLUME_PANEL, wxDefaultPosition, wxDefaultSize);
+ mm_Slider = new wxSlider(mm_SliderPanel, IDS_VOLUME, 125, 0, 255, wxDefaultPosition, wxDefaultSize);
+ //mm_Slider->SetToolTip("Change the music volume");
+ mm_Slider->SetValue(MusicMod::GlobalVolume);
+
+ wxStaticText * mm_SliderText = new wxStaticText(mm_SliderPanel, IDS_VOLUME_LABEL, _T("Volume"), wxDefaultPosition, wxDefaultSize);
+ wxBoxSizer * mm_VolSizer = new wxBoxSizer(wxVERTICAL);
+ mm_VolSizer->Add(mm_Slider, 0, wxEXPAND | wxALL, 0);
+ mm_VolSizer->Add(mm_SliderText, 0, wxCENTER | wxALL, 0);
+
+ mm_SliderPanel->SetSizer(mm_VolSizer);
+ mm_SliderPanel->SetSize(mm_VolSizer->GetMinSize().GetWidth(), mm_VolSizer->GetMinSize().GetHeight());
+
+ toolBar->AddControl((wxControl*)mm_SliderPanel);
+ // ---------
+
+ mm_ToolLog = toolBar->AddTool(IDT_LOG, _T("Log"), m_Bitmaps[Toolbar_Log],
+ wxT("Show or hide log. Enable the log window and restart Dolphin to show the DLL status."));
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Update GUI
+// ŻŻŻŻŻŻŻŻŻŻ
+void
+CFrame::MM_UpdateGUI()
+{
+ if(MusicMod::GlobalMute)
+ {
+ mm_ToolMute->SetLabel("Unmute");
+ mm_ToolMute->SetNormalBitmap(m_Bitmaps[Toolbar_PluginDSP_Dis]);
+ }
+ else
+ {
+ mm_ToolMute->SetLabel("Mute");
+ mm_ToolMute->SetNormalBitmap(m_Bitmaps[Toolbar_PluginDSP]);
+ }
+
+ if(MusicMod::GlobalPause)
+ {
+ mm_ToolPlay->SetLabel("Play");
+ mm_ToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Play]);
+ }
+ else
+ {
+ mm_ToolPlay->SetLabel("Pause");
+ mm_ToolPlay->SetNormalBitmap(m_Bitmaps[Toolbar_Pause]);
+ }
+
+ if(MusicMod::bShowConsole)
+ {
+ mm_ToolLog->SetNormalBitmap(m_Bitmaps[Toolbar_Log]);
+ }
+ else
+ {
+ mm_ToolLog->SetNormalBitmap(m_Bitmaps[Toolbar_Log_Dis]);
+ }
+}
+//////////////////////////////////
+
+
+
+// =======================================================================================
+// Play and stop music
+// ---------------------------------------------------------------------------------------
+void
+CFrame::MM_OnPlay()
+{
+ //INFO_LOG(AUDIO,"\nCFrame::OnPlayMusicMod > Begin\n");
+
+ // Save the volume
+ MusicMod::GlobalVolume = mm_Slider->GetValue();
+
+ IniFile file;
+ file.Load("Plainamp.ini");
+ file.Set("Plainamp", "Volume", MusicMod::GlobalVolume);
+ file.Save("Plainamp.ini");
+
+ if (Core::GetState() != Core::CORE_UNINITIALIZED)
+ {
+ if (Core::GetState() == Core::CORE_RUN)
+ {
+ //INFO_LOG(AUDIO,"CFrame::OnPlayMusicMod > Pause\n");
+ if(!MusicMod::GlobalPause) // we may has set this elsewhere
+ {
+ MusicMod::GlobalPause = true;
+ if (MusicMod::dllloaded)
+ {
+ Player_Pause();
+ }
+ }
+ }
+ else
+ {
+ //INFO_LOG(AUDIO,"CFrame::OnPlayMusicMod > Play\n");
+ if(MusicMod::GlobalPause) // we may has set this elsewhere
+ {
+ MusicMod::GlobalPause = false;
+ if (MusicMod::dllloaded)
+ {
+ Player_Unpause();
+ }
+ }
+ }
+ }
+}
+
+void
+CFrame::MM_OnStop()
+{
+ Player_Stop();
+ MusicMod::GlobalPause = false;
+}
+// =======================================================================================
+
+
+// =======================================================================================
+// Mute music
+// ---------------------------------------------------------------------------------------
+void
+CFrame::MM_OnMute(wxCommandEvent& WXUNUSED (event))
+{
+ //INFO_LOG(AUDIO,"CFrame::OnMute > Begin\n");
+ //MessageBox(0, "", "", 0);
+
+ if(!MusicMod::GlobalMute)
+ {
+ if(MusicMod::dllloaded) // avoid crash
+ {
+ Player_Mute(MusicMod::GlobalVolume);
+ }
+
+ MusicMod::GlobalMute = true;
+ UpdateGUI();
+ }
+ else
+ {
+ if(MusicMod::dllloaded) // avoid crash
+ {
+ Player_Mute(MusicMod::GlobalVolume);
+ }
+ MusicMod::GlobalMute = false;
+ UpdateGUI();
+ }
+}
+// =======================================================================================
+
+
+// =======================================================================================
+// Pause music
+// ---------------------------------------------------------------------------------------
+void
+CFrame::MM_OnPause(wxCommandEvent& WXUNUSED (event))
+{
+ INFO_LOG(AUDIO,"CFrame::OnPause > Begin\n");
+ //MessageBox(0, "", "", 0);
+
+ if(!MusicMod::GlobalPause)
+ {
+ if(MusicMod::dllloaded) // avoid crash
+ {
+ Player_Pause();
+ }
+ MusicMod::GlobalPause = true;
+ UpdateGUI();
+ }
+ else
+ {
+ if(MusicMod::dllloaded) // avoid crash
+ {
+ Player_Pause();
+ }
+ MusicMod::GlobalPause = false;
+ UpdateGUI();
+ }
+}
+
+
+
+
+// =======================================================================================
+// Change volume
+// ---------------------------------------------------------------------------------------
+void CFrame::MM_OnVolume(wxScrollEvent& event)
+{
+ //INFO_LOG(AUDIO,"CFrame::OnVolume > Begin <%i>\n", event.GetPosition());
+ //MessageBox(0, "", "", 0);
+
+ //if(event.GetEventType() == wxEVT_SCROLL_PAGEUP || event.GetEventType() == wxEVT_SCROLL_PAGEDOWN)
+ // return;
+
+ if(MusicMod::dllloaded) // avoid crash
+ {
+
+ Player_Volume(event.GetPosition());
+ MusicMod::GlobalVolume = event.GetPosition();
+
+ MusicMod::GlobalMute = false; // Unmute to
+ mm_ToolMute->Toggle(false);
+
+
+ if(event.GetEventType() == wxEVT_SCROLL_CHANGED)
+ {
+ // Only update this on release, to avoid major flickering when changing volume
+ UpdateGUI();
+
+ /* Use this to avoid that the focus get stuck on the slider when the main
+ window has been replaced */
+ this->SetFocus();}
+ }
+}
+//=======================================================================================
+
+
+
+// =======================================================================================
+// Show log
+// ---------------------------------------------------------------------------------------
+void CFrame::MM_OnLog(wxCommandEvent& event)
+{
+ //INFO_LOG(AUDIO,"CFrame::OnLog > Begin\n");
+ //MessageBox(0, "", "", 0);
+
+ if(!MusicMod::dllloaded) return; // Avoid crash
+
+ MusicMod::bShowConsole = !MusicMod::bShowConsole;
+
+ if(MusicMod::bShowConsole)
+ /* What we do here is run StartConsoleWin() in Common directly after each
+ other first in the exe then in the DLL, sometimes this would give me a rampant memory
+ usage increase until the exe crashed at 700 MB memory usage or something like that.
+ For that reason I'm trying to sleep for a moment between them here. */
+ { MusicMod::ShowConsole(); Sleep(100); Player_Console(true); }
+ else
+ {
+ #if defined (_WIN32)
+ Console::Close(); Player_Console(false);
+ #endif
+ }
+
+ IniFile file;
+ file.Load("Plainamp.ini");
+ file.Set("Interface", "ShowConsole", MusicMod::bShowConsole);
+ file.Save("Plainamp.ini");
+
+ UpdateGUI();
+}
+//=======================================================================================
+
+#endif // MUSICMOD
diff --git a/Externals/MusicMod/Main/Src/Main.cpp b/Externals/MusicMod/Main/Src/Main.cpp
new file mode 100644
index 0000000000..89d95367a2
--- /dev/null
+++ b/Externals/MusicMod/Main/Src/Main.cpp
@@ -0,0 +1,342 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Include
+// ŻŻŻŻŻŻŻŻŻŻ
+#include
+#include
+#include
+#include
+
+#include "Common.h" // Common
+#include "IniFile.h"
+#include "Log.h"
+
+#include "PowerPC/PowerPc.h" // Core
+
+#include "../../../../Source/Core/DiscIO/Src/FileSystemGCWii.h" // This file has #include "Filesystem.h"
+#include "../../../../Source/Core/DiscIO/Src/VolumeCreator.h"
+
+#include "../../Player/Src/PlayerExport.h" // Local player
+//////////////////////////////////
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations and definitions
+// ŻŻŻŻŻŻŻŻŻŻ
+namespace MusicMod
+{
+
+struct MyFilesStructure
+{
+ std::string path;
+ int offset; // Is int enough, how high does offset go?
+};
+
+std::vector MyFiles;
+void StructSort (std::vector &MyFiles);
+
+
+// Playback
+std::string CurrentFile;
+std::string CurrentPlayFile;
+std::string CurrentPlayFilePath;
+std::string unique_gameid;
+
+std::string MusicPath;
+
+DiscIO::CFileSystemGCWii* my_pFileSystem;
+
+int WritingFile = false;
+bool dllloaded = false;
+
+extern bool bShowConsole; // Externally define
+extern int GlobalVolume;
+//////////////////////////////////
+
+
+// =======================================================================================
+// Supported music files
+// ---------------------------------------------------------------------------------------
+bool CheckFileEnding(std::string FileName)
+{
+ if (
+ (FileName.find(".adp") != std::string::npos) // 1080 Avalanche, Crash Bandicoot etc
+ || (FileName.find(".afc") != std::string::npos) // Zelda WW
+ || (FileName.find(".ast") != std::string::npos) // Zelda TP, Mario Kart
+ || (FileName.find(".dsp") != std::string::npos) // Metroid Prime
+ || (FileName.find(".hps") != std::string::npos) // SSB Melee
+ )
+ return true;
+
+ return false;
+}
+// =======================================================================================
+
+
+// =======================================================================================
+// A function to sort the filelist table after offset
+// ------------------------
+void StructSort (std::vector &MyFiles)
+{
+ MyFilesStructure temp;
+
+ //INFO_LOG(AUDIO,"StructSort > Begin\n");
+
+ for(int i = 0; i < MyFiles.size() - 1; i++)
+ {
+ for (int j = i + 1; j < MyFiles.size(); j++)
+ {
+ if (MyFiles[ i ].offset > MyFiles[ j ].offset) //comparing cost
+ {
+ temp = MyFiles[ i ]; // Swapping entire struct
+ MyFiles[ i ] = MyFiles[ j ];
+ MyFiles[ j ] = temp;
+ }
+ }
+ }
+
+
+ for (long i=1; i<(long)MyFiles.size(); ++i)
+ {
+ std::cout << i << " " << MyFiles[i].path.c_str() << "#" << MyFiles[i].offset << "\n";
+ }
+
+ //INFO_LOG(AUDIO,"StructSort > Done\n");
+}
+// ============================
+
+
+// =======================================================================================
+/* Run these things once */
+// ------------------------
+void ShowConsole()
+{
+// Console::Open(100, 2000, "MusicMod", true); // Give room for 2000 rows
+}
+
+void Init()
+{
+ // These things below will not need to be updated after a new game is started
+ if (dllloaded) return;
+
+ // ---------------------------------------
+ // Load config
+ // ---------------------
+ IniFile file;
+ file.Load("Plainamp.ini");
+ file.Get("Interface", "ShowConsole", &MusicMod::bShowConsole, false);
+ file.Get("Plainamp", "Volume", &MusicMod::GlobalVolume, 125);
+ // -------
+
+ // ---------------------------------------
+ // Make a debugging window
+ // ---------------------
+ if(MusicMod::bShowConsole) ShowConsole();
+
+ // Write version
+ #ifdef _M_X64
+ INFO_LOG(AUDIO,"64 bit version\n");
+ #else
+ INFO_LOG(AUDIO,"32 bit version\n");
+ #endif
+ // -----------
+
+ // Set volume
+ Player_Volume(MusicMod::GlobalVolume);
+
+ // Show DLL status
+ Player_Main(MusicMod::bShowConsole);
+ //play_file("c:\\demo36_02.ast");
+ //INFO_LOG(AUDIO,"DLL loaded\n");
+
+ dllloaded = true; // Do this once
+}
+// ============================
+
+
+// =======================================================================================
+/* This will read the GC file system. */
+// ------------------------
+void Main(std::string FileName)
+{
+ //
+ DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(FileName.c_str());
+
+ //
+ my_pFileSystem = new DiscIO::CFileSystemGCWii(pVolume);
+
+ /* We have to sort the files according to offset so that out scan in Blob.cpp works.
+ Because StructSort() only works for MyFilesStructure I copy the offset and filenames
+ to a new vetor first. */
+ MyFiles.resize(my_pFileSystem->m_FileInfoVector.size()); // Set size
+ for (size_t i = 0; i < my_pFileSystem->m_FileInfoVector.size(); i++)
+ {
+ MyFiles.at(i).offset = my_pFileSystem->m_FileInfoVector.at(i).m_Offset;
+ MyFiles.at(i).path = my_pFileSystem->m_FileInfoVector.at(i).m_FullPath;
+ }
+
+ // Sort the files by offset
+ StructSort(MyFiles);
+
+ // ---------------------------------------------------------------------------------------
+ // Make Music directory
+ // -------------------------
+ LPSECURITY_ATTRIBUTES attr;
+ attr = NULL;
+ MusicPath = "Music\\";
+ INFO_LOG(AUDIO,"Created a Music directory\n");
+ CreateDirectory(MusicPath.c_str(), attr);
+ // ----------------------------------------------------------------------------------------
+}
+
+
+// =======================================================================================
+// Check if we should play this file
+// ---------------------------------------------------------------------------------------
+void CheckFile(std::string File, int FileNumber)
+{
+ // Do nothing if we found the same file again
+ if (CurrentFile == File) return;
+
+ //INFO_LOG(AUDIO,">>>> (%i)Current read %s <%u = %ux%i> \n", i, CurrentFiles[i].path.c_str(), offset, CurrentFiles[i].offset, size);
+
+ // Check if it's a music file
+ if (CheckFileEnding(File.c_str()))
+ {
+ /* Don't restart the playback if we find the same music file again. If the game is playing
+ a streaming music file it may read from it once in a while, after it has read other
+ files in between, if did not do this check we would restart the playback in those cases */
+ if (CurrentPlayFile == File) return;
+
+ // Notify the user
+ INFO_LOG(AUDIO,"\n >>> (%i/%i) Match %s\n\n", FileNumber, MyFiles.size(), File.c_str());
+
+ // Save the matched file
+ CurrentPlayFile = File;
+
+ // ---------------------------------------------------------------------------------------
+ // We will now save the file to the PC hard drive
+ // ------------------
+ // Get the filename
+ std::size_t pointer = File.find_last_of("\\");
+ std::string fragment = File.substr (0, (pointer-0));
+ int compare = File.length() - fragment.length(); // Get the length of the filename
+ fragment = File.substr ((pointer+1), compare); // Now we have the filename
+
+ // Create the target file path
+ std::string FilePath = (MusicPath + fragment);
+
+ WritingFile = true; // Avoid detecting the file we are writing
+ INFO_LOG(AUDIO,"Writing <%s> to <%s>\n", File.c_str(), FilePath.c_str());
+ my_pFileSystem->ExportFile(File.c_str(), FilePath.c_str());
+ WritingFile = false;
+
+ // ---------------------------------------------------------------------------------------
+ // Play the file we found
+ // ------------------
+ if(dllloaded)
+ {
+ Player_Play((char*)FilePath.c_str()); // retype it from const char* to char*
+ } else {
+ INFO_LOG(AUDIO,"Warning > Music DLL is not loaded");
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Remove the last file, if any
+ // ------------------
+ if(CurrentPlayFilePath.length() > 0)
+ {
+ if(!remove(CurrentPlayFilePath.c_str()))
+ {
+ INFO_LOG(AUDIO,"The program failed to remove <%s>\n", CurrentPlayFilePath.c_str());
+ } else {
+ INFO_LOG(AUDIO,"The program removed <%s>\n", CurrentPlayFilePath.c_str());
+ }
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Save the current playing file
+ // ------------------
+ CurrentPlayFilePath = FilePath; // Save the filename so we can remove it later
+ }
+
+ // Tell the user about the files we ignored
+ INFO_LOG(AUDIO,"(%i/%i) Ignored %s\n", FileNumber, MyFiles.size(), File.c_str());
+
+ // Update the current file
+ CurrentFile = File;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Find the current filename for a certain offset on the GC fileystem
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void FindFilename(u64 offset, u64 size)
+{
+ // =======================================================================================
+ /* Only do this test:
+ 1. After boot, not on ISO scan
+ 2. Not if offset = 0.
+ 3. Not when WritingFile. We will lead to calls back to here (Read) and it will mess
+ upp the scanning */
+ if(PowerPC::GetState() == PowerPC::CPUState::CPU_RUNNING && offset != 0 && !WritingFile)
+ {
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ /* Get the filename. Here we go through all files until we come to the file that has
+ the matching offset. Before MyFiles has data this loop will go nowhere. We have to
+ specify (MyFiles.size() - 1) because we will be reading MyFiles.at(i + 1).
+ MyFiles.size() is the amount of files on the disc, and the last file is
+ MyFiles.at(MyFiles.size() - 1) */
+ // ---------------------------------------------------------------------------------------
+ for (int i = 0; i < (int)(MyFiles.size() - 1); ++i)
+ {
+ // ---------------------------------------------------------------------------------------
+ /* If we assume that myoffset is the begginning of every file this works.
+ Suppose there are three files
+ 1 is 0 to 149
+ 2 is 150 to 170
+ 3 is 171 to 200
+ If the offset is 160 the game is reading file number two, for example
+ myoffset = 150: (myoffset >= offset) == false
+ myoffset = 171: (myoffset >= offset) == true, break
+
+ However if the offset is 195 the game is reading the last file and we will get
+ myoffset = 171: (myoffset >= offset) == false
+ we therefore need to add the condition (offset > MyFiles[MyFiles.size() - 1].offset)
+ to. */
+ if (MyFiles[i + 1].offset >= offset || offset > MyFiles[MyFiles.size() - 1].offset)
+ {
+ // Now we know that the game is reading from MyFiles[i].path
+ CheckFile(MyFiles[i].path, i);
+
+ // Stop checking
+ break;
+ }
+ }
+ } // This ends the entire filescan
+ // =======================================================================================
+}
+/////////////////////////////////
+
+
+} // end of namespace
diff --git a/Externals/MusicMod/Main/Src/Main.h b/Externals/MusicMod/Main/Src/Main.h
new file mode 100644
index 0000000000..92ea473507
--- /dev/null
+++ b/Externals/MusicMod/Main/Src/Main.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+#include // System: For std
+
+#include "Common.h" // Common: For u64
+
+
+namespace MusicMod
+{
+
+void Main(std::string FileName);
+void FindFilename(u64 offset, u64 size);
+void CheckFile(std::string File, int FileNumber = 0);
+
+}
\ No newline at end of file
diff --git a/Externals/MusicMod/Player/Lib/fftw3.lib b/Externals/MusicMod/Player/Lib/fftw3.lib
new file mode 100644
index 0000000000..0fe0789d9a
Binary files /dev/null and b/Externals/MusicMod/Player/Lib/fftw3.lib differ
diff --git a/Externals/MusicMod/Player/Lib/libzlib1.lib b/Externals/MusicMod/Player/Lib/libzlib1.lib
new file mode 100644
index 0000000000..e58100e822
Binary files /dev/null and b/Externals/MusicMod/Player/Lib/libzlib1.lib differ
diff --git a/Externals/MusicMod/Player/Player.vcproj b/Externals/MusicMod/Player/Player.vcproj
new file mode 100644
index 0000000000..4b7df6c15f
--- /dev/null
+++ b/Externals/MusicMod/Player/Player.vcproj
@@ -0,0 +1,925 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Externals/MusicMod/Player/Src/AddDirectory.cpp b/Externals/MusicMod/Player/Src/AddDirectory.cpp
new file mode 100644
index 0000000000..17dd6de1d8
--- /dev/null
+++ b/Externals/MusicMod/Player/Src/AddDirectory.cpp
@@ -0,0 +1,364 @@
+////////////////////////////////////////////////////////////////////////////////
+// Plainamp, Open source Winamp core
+//
+// Copyright İ 2005 Sebastian Pipping
+//
+// --> http://www.hartwork.org
+//
+// This source code is released under the GNU General Public License (GPL).
+// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include "AddDirectory.h"
+#include "Playlist.h"
+#include "Main.h"
+#include "InputPlugin.h"
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+
+
+HWND WindowBrowse = NULL;
+
+
+
+void SearchFolder( TCHAR * szPath );
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+LPITEMIDLIST GetCurrentFolder()
+{
+/*
+ How To Convert a File Path to an ITEMIDLIST
+ http://support.microsoft.com/default.aspx?scid=kb;en-us;132750
+*/
+ LPITEMIDLIST pidl;
+ LPSHELLFOLDER pDesktopFolder;
+ TCHAR szPath[ MAX_PATH ];
+#ifndef PA_UNICODE
+ OLECHAR olePath[ MAX_PATH ];
+#endif
+ ULONG chEaten;
+ ULONG dwAttributes;
+ HRESULT hr;
+
+ //
+ // Get the path we need to convert.
+ //
+ GetCurrentDirectory( MAX_PATH, szPath );
+
+ //
+ // Get a pointer to the Desktop's IShellFolder interface.
+ //
+ if( SUCCEEDED( SHGetDesktopFolder( &pDesktopFolder ) ) )
+ {
+
+ //
+ // IShellFolder::ParseDisplayName requires the file name be in
+ // Unicode.
+ //
+#ifndef PA_UNICODE
+ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, olePath, MAX_PATH );
+#endif
+ //
+ // Convert the path to an ITEMIDLIST.
+ //
+ // hr = pDesktopFolder->lpVtbl->ParseDisplayName(
+ hr = pDesktopFolder->ParseDisplayName(
+ ( HWND__ * )pDesktopFolder,
+ NULL,
+#ifndef PA_UNICODE
+ olePath,
+#else
+ szPath,
+#endif
+ &chEaten,
+ &pidl,
+ &dwAttributes
+ );
+
+ if( FAILED( hr ) )
+ {
+ // Handle error.
+ return NULL;
+ }
+
+ //
+ // pidl now contains a pointer to an ITEMIDLIST for .\readme.txt.
+ // This ITEMIDLIST needs to be freed using the IMalloc allocator
+ // returned from SHGetMalloc().
+ //
+
+ // release the desktop folder object
+ // pDesktopFolder->lpVtbl->Release();
+ pDesktopFolder->Release();
+
+ return pidl;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lp )
+{
+ TCHAR szClassName[ 8 ] = TEXT( "\0" );
+ HWND * hFirstFoundStatic = ( ( HWND * )lp );
+
+ if( GetClassName( hwnd, szClassName, 7 ) )
+ {
+ if( !_tcscmp( szClassName, TEXT( "Static" ) ) )
+ {
+ if( *hFirstFoundStatic )
+ {
+ // Both found
+ RECT r1;
+ GetWindowRect( *hFirstFoundStatic, &r1 );
+
+ RECT r2;
+ GetWindowRect( hwnd, &r2 );
+
+ // First must be taller one
+ if( r1.bottom - r1.top < r2.bottom - r2.top )
+ {
+ // Swap
+ RECT r = r1;
+ HWND h = *hFirstFoundStatic;
+
+ r1 = r2;
+ *hFirstFoundStatic = hwnd;
+
+ r2 = r;
+ hwnd = h;
+ }
+
+ POINT xy2 = { r2.left, r2.top };
+ ScreenToClient( WindowBrowse, &xy2 );
+
+ SetWindowPos(
+ *hFirstFoundStatic,
+ NULL,
+ 0,
+ 0,
+ r2.right - r2.left,
+ r2.bottom - r2.top,
+ SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER
+ );
+
+ SetWindowPos(
+ hwnd,
+ NULL,
+ xy2.x,
+ xy2.y + ( r2.bottom - r2.top ) - ( r1.bottom - r1.top ),
+ r1.right - r1.left,
+ r1.bottom - r1.top,
+ SWP_NOOWNERZORDER | SWP_NOZORDER
+ );
+
+
+ return FALSE; // Stop
+ }
+ else
+ {
+ // First found
+ *hFirstFoundStatic = hwnd;
+ }
+ }
+ }
+
+ return TRUE; // Continue
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+int CALLBACK BrowseCallbackProc( HWND hwnd, UINT message, LPARAM lp, LPARAM wp )
+{
+ switch( message )
+ {
+ case BFFM_INITIALIZED:
+ {
+ WindowBrowse = hwnd;
+
+ // Init with curdir
+ SendMessage( hwnd, BFFM_SETSELECTION, FALSE, ( LPARAM )GetCurrentFolder() );
+
+ // Swap static dimensions
+ HWND hFirstFoundStatic = NULL;
+ EnumChildWindows( hwnd, EnumChildProc, ( LPARAM )&hFirstFoundStatic );
+
+ break;
+ }
+
+ case BFFM_SELCHANGED:
+ {
+ TCHAR szPath[ MAX_PATH ] = TEXT( "\0" );
+ SHGetPathFromIDList( ( LPITEMIDLIST )lp, szPath );
+ SendMessage( hwnd, BFFM_SETSTATUSTEXT, 0, ( LPARAM )szPath );
+
+ break;
+ }
+
+ case BFFM_VALIDATEFAILED:
+ return TRUE;
+
+ }
+
+ return 0;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Shows a Browse-For-Folder dialog and recursively adds supported files
+/// to the playlist. Files are sorted by full filaname before being added.
+////////////////////////////////////////////////////////////////////////////////
+void AddDirectory()
+{
+ TCHAR szPath[ MAX_PATH ];
+ BROWSEINFO bi = { 0 };
+ bi.hwndOwner = WindowMain;
+ bi.pidlRoot = NULL; // Desktop folder
+ bi.lpszTitle = TEXT( "Please select a directory:" );
+ bi.ulFlags = BIF_VALIDATE | BIF_STATUSTEXT;
+ bi.lpfn = BrowseCallbackProc;
+
+ LPITEMIDLIST pidl = SHBrowseForFolder( &bi );
+ if( !pidl ) return;
+
+ // Get path
+ SHGetPathFromIDList( pidl, szPath );
+
+
+ // Search
+ SearchFolder( szPath );
+
+
+ // Stay here
+ SetCurrentDirectory( szPath );
+
+
+ // Free memory used
+ IMalloc * imalloc = 0;
+ if( SUCCEEDED( SHGetMalloc( &imalloc ) ) )
+ {
+ imalloc->Free( pidl );
+ imalloc->Release();
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/* Warning: There is SetCurrentDirectory() here, be aware of it. We don't really
+ want to use that. */
+////////////////////////////////////////////////////////////////////////////////
+void SearchFolder( TCHAR * szPath )
+{
+ // Remove trailing backslash
+ int iPathLen = ( int )_tcslen( szPath );
+ if( iPathLen < 1 ) return;
+ if( szPath[ iPathLen - 1 ] == TEXT( '\\' ) )
+ {
+ iPathLen--;
+ }
+
+ // Init working buffer
+ TCHAR szFullpath[ MAX_PATH ];
+ memcpy( szFullpath, szPath, iPathLen * sizeof( TCHAR ) );
+ szFullpath[ iPathLen ] = TEXT( '\\' );
+ szFullpath[ iPathLen + 1 ] = TEXT( '\0' );
+
+ // Make pattern
+ _tcscpy( szFullpath + iPathLen + 1, TEXT( "*" ) );
+
+ // Find
+ vector Files;
+ vector Dirs;
+ WIN32_FIND_DATA FindFileData;
+ HANDLE hFind;
+ hFind = FindFirstFile( szFullpath, &FindFileData );
+ if( hFind == INVALID_HANDLE_VALUE ) return;
+
+ do
+ {
+ // Skip "." and ".."
+ if( !_tcscmp( FindFileData.cFileName, TEXT( "." ) ) ||
+ !_tcscmp( FindFileData.cFileName, TEXT( ".." ) ) ) continue;
+
+ // Make full path
+ _tcscpy( szFullpath + iPathLen + 1, FindFileData.cFileName );
+
+ // Is directory?
+ TCHAR * szPartname = new TCHAR[ MAX_PATH ];
+ _tcscpy( szPartname, FindFileData.cFileName );
+ if( SetCurrentDirectory( szFullpath ) )
+ {
+ // New dir
+ Dirs.push_back( szPartname );
+ continue;
+ }
+
+ // Search "."
+ const int iFilenameLen = ( int )_tcslen( FindFileData.cFileName );
+ TCHAR * szExt = FindFileData.cFileName + iFilenameLen - 1;
+ while( ( szExt > FindFileData.cFileName ) && ( *szExt != TEXT( '.' ) ) ) szExt--;
+ if( *szExt != TEXT( '.' ) ) continue;
+ szExt++;
+
+ // Check extension
+ map ::iterator iter = ext_map.find( szExt );
+ if( iter == ext_map.end() ) continue;
+
+ // New file
+ Files.push_back( szPartname );
+ }
+ while( FindNextFile( hFind, &FindFileData ) );
+
+ FindClose( hFind );
+ vector ::iterator iter;
+
+ // Sort and recurse directories
+ sort( Dirs.begin(), Dirs.end(), TextCompare() );
+ iter = Dirs.begin();
+ while( iter != Dirs.end() )
+ {
+ TCHAR * szWalk = *iter;
+
+ _tcscpy( szFullpath + iPathLen + 1, szWalk );
+ SearchFolder( szFullpath );
+
+ iter++;
+ }
+
+ // Sort and add files
+ sort( Files.begin(), Files.end(), TextCompare() );
+ iter = Files.begin();
+ while( iter != Files.end() )
+ {
+ TCHAR * szWalk = *iter;
+
+ TCHAR * szKeep = new TCHAR[ MAX_PATH ];
+ memcpy( szKeep, szFullpath, ( iPathLen + 1 ) * sizeof( TCHAR ) );
+ _tcscpy( szKeep + iPathLen + 1, szWalk );
+ playlist->PushBack( szKeep );
+
+ iter++;
+ }
+}
diff --git a/Externals/MusicMod/Player/Src/AddDirectory.h b/Externals/MusicMod/Player/Src/AddDirectory.h
new file mode 100644
index 0000000000..8c819cbd63
--- /dev/null
+++ b/Externals/MusicMod/Player/Src/AddDirectory.h
@@ -0,0 +1,26 @@
+////////////////////////////////////////////////////////////////////////////////
+// Plainamp, Open source Winamp core
+//
+// Copyright İ 2005 Sebastian Pipping
+//
+// --> http://www.hartwork.org
+//
+// This source code is released under the GNU General Public License (GPL).
+// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef PA_ADD_DIRECTORY_H
+#define PA_ADD_DIRECTORY_H
+
+
+
+#include "Global.h"
+
+
+
+void AddDirectory();
+
+
+
+#endif // PA_ADD_DIRECTORY_H
diff --git a/Externals/MusicMod/Player/Src/AddFiles.cpp b/Externals/MusicMod/Player/Src/AddFiles.cpp
new file mode 100644
index 0000000000..d8367894b2
--- /dev/null
+++ b/Externals/MusicMod/Player/Src/AddFiles.cpp
@@ -0,0 +1,181 @@
+////////////////////////////////////////////////////////////////////////////////
+// Plainamp, Open source Winamp core
+//
+// Copyright İ 2005 Sebastian Pipping
+//
+// --> http://www.hartwork.org
+//
+// This source code is released under the GNU General Public License (GPL).
+// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include "AddFiles.h"
+#include "InputPlugin.h"
+#include "Main.h"
+#include "Playlist.h"
+#include
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+void AddFiles()
+{
+ int total = 0;
+
+ int iFilterLen = 0;
+
+ InputPlugin * input;
+ vector ::iterator iter;
+
+ // Get len
+// if( input_plugins.empty() ) return;
+ iter = input_plugins.begin();
+ while( iter != input_plugins.end() )
+ {
+ input = *iter;
+ if( !input ) iter++;
+ iFilterLen += input->iFiltersLen;
+ iter++;
+ }
+
+// if( !iFilterLen ) return;
+
+ iFilterLen += 40 + 29 + ( int )ext_map.size() * ( 2 + 4 + 1 ) + 7;
+
+ TCHAR * szFilters = new TCHAR[ iFilterLen ];
+ TCHAR * walk = szFilters;
+
+ // ..................1.........1....\....\.1.........1........\.1...
+ memcpy( walk, TEXT( "All files (*.*)\0*.*\0All supported types\0" ), 40 * sizeof( TCHAR ) );
+ walk += 40;
+
+ // Add all extensions as ";*.ext"
+// if( ext_map.empty() ) return;
+ map ::iterator iter_ext = ext_map.begin();
+ bool bFirst = true;
+ while( iter_ext != ext_map.end() )
+ {
+ if( !bFirst )
+ {
+ memcpy( walk, TEXT( ";*." ), 3 * sizeof( TCHAR ) );
+ walk += 3;
+ }
+ else
+ {
+ memcpy( walk, TEXT( "*." ), 2 * sizeof( TCHAR ) );
+ walk += 2;
+ bFirst = false;
+ }
+
+ TCHAR * szExt = iter_ext->first;
+ int uLen = ( int )_tcslen( szExt );
+ memcpy( walk, szExt, uLen * sizeof( TCHAR ) );
+ walk += uLen;
+
+ iter_ext++;
+ }
+
+ // *walk = TEXT( '\0' );
+ // walk++;
+
+ // ..................1..........1...
+ memcpy( walk, TEXT( ";*.m3u\0" ), 7 * sizeof( TCHAR ) );
+ walk += 7;
+
+ // ..................1.........1.........1...........1...
+ memcpy( walk, TEXT( "Playlist files (*.M3U)\0*.m3u\0" ), 29 * sizeof( TCHAR ) );
+ walk += 29;
+
+ // Copy filters
+ iter = input_plugins.begin();
+ while( iter != input_plugins.end() )
+ {
+ input = *iter;
+ if( !input ) iter++;
+ memcpy( walk, input->szFilters, input->iFiltersLen * sizeof( TCHAR ) );
+ walk += input->iFiltersLen;
+ iter++;
+ }
+
+ *walk = TEXT( '\0' );
+ walk++;
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+ static TCHAR szFilenames[ 20001 ];
+ *szFilenames = TEXT( '\0' ); // Each time!
+
+ OPENFILENAME ofn;
+ memset( &ofn, 0, sizeof( OPENFILENAME ) );
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.hwndOwner = WindowMain;
+ ofn.hInstance = g_hInstance;
+ ofn.lpstrFilter = szFilters; // "MPEG Layer 3\0*.mp3\0";
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 2;
+ ofn.lpstrFile = szFilenames;
+ ofn.nMaxFile = 20000;
+ ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFileTitle = 0, // NULL;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = TEXT( "Add files" );
+
+ if( !GetOpenFileName( &ofn ) ) return;
+
+ int uDirLen = ( int )_tcslen( szFilenames );
+ TCHAR * szDir = szFilenames;
+
+ TCHAR * szFileWalk = szDir + uDirLen + 1;
+ if( *szFileWalk == TEXT( '\0' ) ) // "\0\0" or just "\0"?
+ {
+ // \0\0 -> Single file
+ if( !_tcsncmp( szDir + uDirLen - 3, TEXT( "m3u" ), 3 ) )
+ {
+ // Playlist file
+ Playlist::AppendPlaylistFile( szDir );
+ }
+ else
+ {
+ // Music file
+ TCHAR * szKeep = new TCHAR[ uDirLen + 1 ];
+ memcpy( szKeep, szDir, uDirLen * sizeof( TCHAR ) );
+ szKeep[ uDirLen ] = TEXT( '\0' );
+ playlist->PushBack( szKeep );
+ }
+ }
+ else
+ {
+ // \0 -> Several files
+ int iFileLen;
+ while( *szFileWalk != TEXT( '\0' ) )
+ {
+ iFileLen = ( int )_tcslen( szFileWalk );
+ if( !iFileLen ) return;
+
+ TCHAR * szKeep = new TCHAR[ uDirLen + 1 + iFileLen + 1 ];
+ memcpy( szKeep, szDir, uDirLen * sizeof( TCHAR ) );
+ szKeep[ uDirLen ] = TEXT( '\\' );
+ memcpy( szKeep + uDirLen + 1, szFileWalk, iFileLen * sizeof( TCHAR ) );
+ szKeep[ uDirLen + 1 + iFileLen ] = TEXT( '\0' );
+
+ if( !_tcsncmp( szKeep + uDirLen + 1 + iFileLen - 3, TEXT( "m3u" ), 3 ) )
+ {
+ // Playlist file
+ Playlist::AppendPlaylistFile( szKeep );
+ delete [] szKeep;
+ }
+ else
+ {
+ // Music file
+ playlist->PushBack( szKeep );
+ }
+
+ szFileWalk += iFileLen + 1;
+ }
+ }
+}
diff --git a/Externals/MusicMod/Player/Src/AddFiles.h b/Externals/MusicMod/Player/Src/AddFiles.h
new file mode 100644
index 0000000000..387242ce1a
--- /dev/null
+++ b/Externals/MusicMod/Player/Src/AddFiles.h
@@ -0,0 +1,26 @@
+////////////////////////////////////////////////////////////////////////////////
+// Plainamp, Open source Winamp core
+//
+// Copyright İ 2005 Sebastian Pipping
+//
+// --> http://www.hartwork.org
+//
+// This source code is released under the GNU General Public License (GPL).
+// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef PA_ADD_FILES_H
+#define PA_ADD_FILES_H
+
+
+
+#include "Global.h"
+
+
+
+void AddFiles();
+
+
+
+#endif // PA_ADD_FILES_H
diff --git a/Externals/MusicMod/Player/Src/Config.cpp b/Externals/MusicMod/Player/Src/Config.cpp
new file mode 100644
index 0000000000..d6b3615bf9
--- /dev/null
+++ b/Externals/MusicMod/Player/Src/Config.cpp
@@ -0,0 +1,687 @@
+////////////////////////////////////////////////////////////////////////////////
+// Plainamp, Open source Winamp core
+//
+// Copyright İ 2005 Sebastian Pipping
+//
+// --> http://www.hartwork.org
+//
+// This source code is released under the GNU General Public License (GPL).
+// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Include and declarations, definitions
+////////////////////////////////////////////////////////////////////////////////
+#include "Config.h"
+#include "Console.h"
+#include