diff --git a/Core/Console.cpp b/Core/Console.cpp index 0073c019..6b1fcb35 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -23,6 +23,7 @@ Console::Console() Console::~Console() { Movie::Stop(); + SoundMixer::StopRecording(); } shared_ptr Console::GetInstance() @@ -140,6 +141,8 @@ uint32_t Console::GetCrc32() void Console::Reset(bool softReset) { Movie::Stop(); + SoundMixer::StopRecording(); + if(Instance->_initialized) { Console::Pause(); if(softReset) { @@ -155,6 +158,7 @@ void Console::Reset(bool softReset) void Console::ResetComponents(bool softReset) { Movie::Stop(); + SoundMixer::StopRecording(); _memoryManager->Reset(softReset); _ppu->Reset(); @@ -277,6 +281,7 @@ void Console::Run() } SoundMixer::StopAudio(); Movie::Stop(); + SoundMixer::StopRecording(); VideoDecoder::GetInstance()->StopThread(); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index e5867cc9..229af0dc 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -185,6 +185,7 @@ MultiThreadedDebugDLL true true + false Console @@ -213,6 +214,7 @@ MultiThreadedDebugDLL true true + false Console @@ -551,6 +553,7 @@ + @@ -611,6 +614,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index f8c4bd2f..77ea3fb5 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1,14 +1,6 @@  - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - {ff3c6e48-3987-41d2-8916-b588a457ff30} @@ -72,11 +64,12 @@ {1d706c9e-639f-4da0-a7ce-50d04b2b6a7e} + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + - - Header Files - Nes\Interfaces @@ -101,9 +94,6 @@ Nes\Mappers - - Header Files - Nes\Interfaces @@ -149,12 +139,6 @@ Debugger - - Header Files - - - Header Files - Nes\Interfaces @@ -185,9 +169,6 @@ Nes\APU - - Header Files - Nes\Mappers @@ -203,9 +184,6 @@ Nes\Interfaces - - Header Files - Nes\Mappers @@ -314,15 +292,9 @@ Nes\Mappers - - Header Files - Nes\Mappers - - Header Files - Nes\Mappers @@ -590,13 +562,40 @@ Nes + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Nes\Mappers + + + Nes\Mappers + + + Misc + - Source Files + Misc - Source Files + Misc Debugger @@ -611,19 +610,19 @@ Debugger - Source Files + Misc - Source Files + Misc - Source Files + Misc Debugger - Source Files + Misc VideoDecoder @@ -739,5 +738,8 @@ Nes + + Misc + \ No newline at end of file diff --git a/Core/MessageManager.cpp b/Core/MessageManager.cpp index be0cfe75..3ae79e36 100644 --- a/Core/MessageManager.cpp +++ b/Core/MessageManager.cpp @@ -15,6 +15,7 @@ std::unordered_map MessageManager::_enResources = { { "NetPlay", u8"Net Play" }, { "SaveStates", u8"Save States" }, { "ScreenshotSaved", u8"Screenshot Saved" }, + { "SoundRecorder", u8"Sound Recorder" }, { "Test", u8"Test" }, { "CheatApplied", u8"1 cheat applied." }, @@ -49,6 +50,8 @@ std::unordered_map MessageManager::_enResources = { { "SaveStateSaved", u8"State #%1 saved." }, { "ServerStarted", u8"Server started (Port: %1)" }, { "ServerStopped", u8"Server stopped" }, + { "SoundRecorderStarted", u8"Recording to: %1" }, + { "SoundRecorderStopped", u8"Recording saved to: %1" }, { "TestFileSavedTo", u8"Test file saved to: %1" }, { "UnsupportedMapper", u8"Unsupported mapper, cannot load game." }, @@ -69,6 +72,7 @@ std::unordered_map MessageManager::_frResources = { { "NetPlay", u8"Jeu en ligne" }, { "SaveStates", u8"Sauvegardes" }, { "ScreenshotSaved", u8"Capture d'écran" }, + { "SoundRecorder", u8"Enregistreur audio" }, { "Test", u8"Test" }, { "CheatApplied", u8"%1 code activé." }, @@ -90,7 +94,7 @@ std::unordered_map MessageManager::_frResources = { { "MovieMissingRom", u8"Le rom (%1) correspondant au film sélectionné est introuvable." }, { "MovieNewerVersion", u8"Impossible de charger un film qui a été créé avec une version plus récente de Mesen. Veuillez mettre à jour Mesen pour jouer ce film." }, { "MovieIncompatibleVersion", u8"Ce film est incompatible avec votre version de Mesen." }, - { "MoviePlaying", u8"Film démarré: %1" }, + { "MoviePlaying", u8"Film démarré : %1" }, { "MovieRecordingTo", u8"En cours d'enregistrement : %1" }, { "MovieSaved", u8"Film sauvegardé : %1" }, { "NetplayVersionMismatch", u8"%1 ne roule pas la même version de Mesen que vous et a été déconnecté automatiquement." }, @@ -101,9 +105,11 @@ std::unordered_map MessageManager::_frResources = { { "SaveStateLoaded", u8"Sauvegarde #%1 chargée." }, { "SaveStateNewerVersion", u8"Impossible de charger une sauvegarde qui a été créée avec une version plus récente de Mesen. Veuillez mettre à jour Mesen." }, { "SaveStateSaved", u8"Sauvegarde #%1 sauvegardée." }, - { "ServerStarted", u8"Le serveur a été démarré (Port: %1)" }, + { "ServerStarted", u8"Le serveur a été démarré (Port : %1)" }, { "ServerStopped", u8"Le serveur a été arrêté" }, - { "TestFileSavedTo", u8"Test sauvegardé: %1" }, + { "SoundRecorderStarted", u8"En cours d'enregistrement : %1" }, + { "SoundRecorderStopped", u8"Enregistrement audio sauvegardé : %1" }, + { "TestFileSavedTo", u8"Test sauvegardé : %1" }, { "UnsupportedMapper", u8"Ce mapper n'est pas encore supporté - le jeu ne peut pas être démarré." }, { "GoogleDrive", u8"Google Drive" }, @@ -123,6 +129,7 @@ std::unordered_map MessageManager::_jaResources = { { "NetPlay", u8"ネットプレー" }, { "SaveStates", u8"クイックセーブ" }, { "ScreenshotSaved", u8"スクリーンショット" }, + { "SoundRecorder", u8"サウンドレコーダー" }, { "Test", u8"テスト" }, { "CheatApplied", u8"チートコード%1個を有効にしました。" }, @@ -157,6 +164,8 @@ std::unordered_map MessageManager::_jaResources = { { "SaveStateSaved", u8"クイックセーブ%1をセーブしました。" }, { "ServerStarted", u8"サーバは起動しました (ポート: %1)" }, { "ServerStopped", u8"サーバは停止しました。" }, + { "SoundRecorderStarted", u8"%1に録音しています。" }, + { "SoundRecorderStopped", u8"録音を終了しました: %1" }, { "TestFileSavedTo", u8"Test file saved to: %1" }, { "UnsupportedMapper", u8"このMapperを使うゲームはロードできません。" }, diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index 118f1336..d0293df2 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -4,6 +4,8 @@ #include "CPU.h" IAudioDevice* SoundMixer::AudioDevice = nullptr; +unique_ptr SoundMixer::_waveRecorder; +SimpleLock SoundMixer::_waveRecorderLock; SoundMixer::SoundMixer() { @@ -71,7 +73,7 @@ void SoundMixer::PlayAudioBuffer(uint32_t time) size_t sampleCount = blip_read_samples(_blipBuf, _outputBuffer, SoundMixer::MaxSamplesPerFrame, 0); if(SoundMixer::AudioDevice) { //Apply low pass filter/volume reduction when in background (based on options) - if(EmulationSettings::CheckFlag(EmulationFlags::InBackground)) { + if(!_waveRecorder && EmulationSettings::CheckFlag(EmulationFlags::InBackground)) { if(EmulationSettings::CheckFlag(EmulationFlags::MuteSoundInBackground)) { _lowPassFilter.ApplyFilter(_outputBuffer, sampleCount, 0, 0); } else if(EmulationSettings::CheckFlag(EmulationFlags::ReduceSoundInBackground)) { @@ -100,6 +102,14 @@ void SoundMixer::PlayAudioBuffer(uint32_t time) } SoundMixer::AudioDevice->PlayBuffer(soundBuffer, (uint32_t)sampleCount, _sampleRate, isStereo); + if(_waveRecorder) { + _waveRecorderLock.AcquireSafe(); + if(_waveRecorder) { + if(!_waveRecorder->WriteSamples(soundBuffer, (uint32_t)sampleCount, _sampleRate, isStereo)) { + _waveRecorder.reset(); + } + } + } } if(EmulationSettings::GetSampleRate() != _sampleRate) { @@ -191,4 +201,21 @@ void SoundMixer::EndFrame(uint32_t time) _timestamps.clear(); memset(_channelOutput, 0, sizeof(_channelOutput)); +} + +void SoundMixer::StartRecording(string filepath) +{ + _waveRecorderLock.AcquireSafe(); + _waveRecorder.reset(new WaveRecorder(filepath, EmulationSettings::GetSampleRate(), EmulationSettings::GetStereoFilter() != StereoFilter::None)); +} + +void SoundMixer::StopRecording() +{ + _waveRecorderLock.AcquireSafe(); + _waveRecorder.reset(); +} + +bool SoundMixer::IsRecording() +{ + return _waveRecorder.get() != nullptr; } \ No newline at end of file diff --git a/Core/SoundMixer.h b/Core/SoundMixer.h index b876cf05..d7330a14 100644 --- a/Core/SoundMixer.h +++ b/Core/SoundMixer.h @@ -3,11 +3,13 @@ #include "EmulationSettings.h" #include "../Utilities/LowPassFilter.h" #include "../Utilities/blip_buf.h" +#include "../Utilities/SimpleLock.h" #include "IAudioDevice.h" #include "Snapshotable.h" #include "StereoPanningFilter.h" #include "StereoDelayFilter.h" #include "ReverbFilter.h" +#include "WaveRecorder.h" class SoundMixer : public Snapshotable { @@ -16,12 +18,15 @@ public: static const uint32_t BitsPerSample = 16; private: + static unique_ptr _waveRecorder; + static SimpleLock _waveRecorderLock; + static IAudioDevice* AudioDevice; static const uint32_t MaxSampleRate = 48000; static const uint32_t MaxSamplesPerFrame = MaxSampleRate / 60; static const uint32_t MaxChannelCount = 6; static const uint32_t ExpansionAudioIndex = MaxChannelCount - 1; - + AudioChannel _expansionAudioType; LowPassFilter _lowPassFilter; StereoPanningFilter _stereoPanning; @@ -63,6 +68,10 @@ public: void SetExpansionAudioType(AudioChannel channel); void AddExpansionAudioDelta(uint32_t time, int8_t delta); + static void StartRecording(string filepath); + static void StopRecording(); + static bool IsRecording(); + static void StopAudio(bool clearBuffer = false); static void RegisterAudioDevice(IAudioDevice *audioDevice); }; diff --git a/Core/WaveRecorder.cpp b/Core/WaveRecorder.cpp new file mode 100644 index 00000000..28ae37e5 --- /dev/null +++ b/Core/WaveRecorder.cpp @@ -0,0 +1,85 @@ +#include "stdafx.h" +#include "WaveRecorder.h" +#include "MessageManager.h" + +WaveRecorder::WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo) +{ + _stream = ofstream(outputFile, ios::out | ios::binary); + _outputFile = outputFile; + _streamSize = 0; + _sampleRate = sampleRate; + _isStereo = isStereo; + WriteHeader(); + + MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStarted", _outputFile); +} + +WaveRecorder::~WaveRecorder() +{ + CloseFile(); +} + +void WaveRecorder::WriteHeader() +{ + _stream << "RIFF"; + uint32_t size = 0; + _stream.write((char*)&size, sizeof(size)); + + _stream << "WAVE"; + _stream << "fmt "; + + uint32_t chunkSize = 16; + _stream.write((char*)&chunkSize, sizeof(chunkSize)); + + uint16_t format = 1; //PCM + uint16_t channelCount = _isStereo ? 2 : 1; + uint16_t bytesPerSample = 2; + uint16_t blockAlign = channelCount * bytesPerSample; + uint32_t byteRate = _sampleRate * channelCount * bytesPerSample; + uint16_t bitsPerSample = bytesPerSample * 8; + + _stream.write((char*)&format, sizeof(format)); + _stream.write((char*)&channelCount, sizeof(channelCount)); + _stream.write((char*)&_sampleRate, sizeof(_sampleRate)); + _stream.write((char*)&byteRate, sizeof(byteRate)); + + _stream.write((char*)&blockAlign, sizeof(blockAlign)); + _stream.write((char*)&bitsPerSample, sizeof(bitsPerSample)); + + _stream << "data"; + _stream.write((char*)&size, sizeof(size)); +} + +bool WaveRecorder::WriteSamples(int16_t * samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +{ + if(_sampleRate != sampleRate || _isStereo != isStereo) { + //Format changed, stop recording + CloseFile(); + return false; + } else { + uint32_t sampleBytes = sampleCount * (isStereo ? 4 : 2); + _stream.write((char*)samples, sampleBytes); + _streamSize += sampleBytes; + return true; + } +} + +void WaveRecorder::UpdateSizeValues() +{ + _stream.seekp(4, ios::beg); + uint32_t fileSize = _streamSize + 36; + _stream.write((char*)&fileSize, sizeof(fileSize)); + + _stream.seekp(40, ios::beg); + _stream.write((char*)&_streamSize, sizeof(_streamSize)); +} + +void WaveRecorder::CloseFile() +{ + if(_stream && _stream.is_open()) { + UpdateSizeValues(); + _stream.close(); + + MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStopped", _outputFile); + } +} diff --git a/Core/WaveRecorder.h b/Core/WaveRecorder.h new file mode 100644 index 00000000..1cb3dabe --- /dev/null +++ b/Core/WaveRecorder.h @@ -0,0 +1,21 @@ +#include "stdafx.h" + +class WaveRecorder +{ +private: + std::ofstream _stream; + uint32_t _streamSize; + uint32_t _sampleRate; + bool _isStereo; + string _outputFile; + + void WriteHeader(); + void UpdateSizeValues(); + void CloseFile(); + +public: + WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo); + ~WaveRecorder(); + + bool WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo); +}; \ No newline at end of file diff --git a/GUI.NET/Config/ConfigManager.cs b/GUI.NET/Config/ConfigManager.cs index 5ebd50e8..0690d9ef 100644 --- a/GUI.NET/Config/ConfigManager.cs +++ b/GUI.NET/Config/ConfigManager.cs @@ -58,6 +58,18 @@ namespace Mesen.GUI.Config } } + public static string WaveFolder + { + get + { + string waveFoler = Path.Combine(ConfigManager.HomeFolder, "Wave"); + if(!Directory.Exists(waveFoler)) { + Directory.CreateDirectory(waveFoler); + } + return waveFoler; + } + } + public static string SaveFolder { get diff --git a/GUI.NET/Dependencies/Font.24.spritefont b/GUI.NET/Dependencies/Font.24.spritefont index 760bd691..895badef 100644 Binary files a/GUI.NET/Dependencies/Font.24.spritefont and b/GUI.NET/Dependencies/Font.24.spritefont differ diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index f237baf9..bd25a5ee 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -3,6 +3,7 @@ All Files (*.*)|*.* Movie files (*.mmo)|*.mmo|All Files (*.*)|*.* + Wave files (*.wav)|*.wav|All Files (*.*)|*.* Palette Files (*.pal)|*.pal|All Files (*.*)|*.* All supported formats (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|ZIP Archives (*.zip)|*.ZIP|All (*.*)|*.* All supported formats (*.nes, *.zip, *.fds, *.ips)|*.NES;*.ZIP;*.IPS;*.FDS|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|ZIP Archives (*.zip)|*.ZIP|IPS Patches (*.ips)|*.IPS|All (*.*)|*.* diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index ce5bbfcc..62f38648 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -67,6 +67,9 @@ Du début du jeu De maintenant Arrêter + Enregistreur audio + Enregistrer... + Arrêter Codes Tests Run... @@ -307,11 +310,12 @@ Tous les fichiers (*.*)|*.* - Films (*.mmo)|*.mmo|All (*.*)|*.* - Fichier de palette (*.pal)|*.pal|All Files (*.*)|*.* - Tous les formats supportés (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|Roms de NES (*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|All (*.*)|*.* - Tous les formats supportés (*.nes, *.zip, *.fds, *.ips)|*.NES;*.ZIP;*.IPS;*.FDS|Roms de NES(*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|Fichiers IPS (*.ips)|*.IPS|All (*.*)|*.* - Fichiers de test (*.mtp)|*.mtp|All (*.*)|*.* + Films (*.mmo)|*.mmo|Tous les fichiers (*.*)|*.* + Fichiers wave (*.wav)|*.wav|Tous les fichiers (*.*)|*.* + Fichier de palette (*.pal)|*.pal|Tous les fichiers (*.*)|*.* + Tous les formats supportés (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|Roms de NES (*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|Tous les fichiers (*.*)|*.* + Tous les formats supportés (*.nes, *.zip, *.fds, *.ips)|*.NES;*.ZIP;*.IPS;*.FDS|Roms de NES(*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|Fichiers IPS (*.ips)|*.IPS|Tous les fichiers (*.*)|*.* + Fichiers de test (*.mtp)|*.mtp|Tous les fichiers (*.*)|*.* Continuer Pause diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index 8dfc5cbb..48d733e4 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -67,6 +67,9 @@ 最初から この時点から 停止 + サウンドレコーダー + 録音 + 停止 チートコード テスト Run... @@ -301,6 +304,7 @@ すべてのファイル (*.*)|*.* 動画 (*.mmo)|*.mmo|すべてのファイル (*.*)|*.* + WAVファイル (*.wav)|*.wav|すべてのファイル (*.*)|*.* パレットファイル (*.pal)|*.pal|すべてのファイル (*.*)|*.* 対応するすべてのファイル (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|すべてのファイル (*.*)|*.* 対応するすべてのファイル (*.nes, *.zip, *.fds, *.ips)|*.NES;*.ZIP;*.IPS;*.FDS|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|IPSファイル (*.ips)|*.IPS|すべてのファイル (*.*)|*.* diff --git a/GUI.NET/Forms/frmMain.Designer.cs b/GUI.NET/Forms/frmMain.Designer.cs index 7f8a0c1a..f1edcb1d 100644 --- a/GUI.NET/Forms/frmMain.Designer.cs +++ b/GUI.NET/Forms/frmMain.Designer.cs @@ -99,6 +99,8 @@ namespace Mesen.GUI.Forms this.mnu2xSaiFilter = new System.Windows.Forms.ToolStripMenuItem(); this.mnuSuper2xSaiFilter = new System.Windows.Forms.ToolStripMenuItem(); this.mnuSuperEagleFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuBilinearInterpolation = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAudioConfig = new System.Windows.Forms.ToolStripMenuItem(); this.mnuInput = new System.Windows.Forms.ToolStripMenuItem(); @@ -130,6 +132,9 @@ namespace Mesen.GUI.Forms this.mnuRecordFromStart = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRecordFromNow = new System.Windows.Forms.ToolStripMenuItem(); this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSoundRecorder = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuWaveRecord = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuWaveStop = new System.Windows.Forms.ToolStripMenuItem(); this.mnuCheats = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator(); this.mnuTests = new System.Windows.Forms.ToolStripMenuItem(); @@ -148,8 +153,6 @@ namespace Mesen.GUI.Forms this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuBilinearInterpolation = new System.Windows.Forms.ToolStripMenuItem(); this.panelRenderer.SuspendLayout(); this.menuStrip.SuspendLayout(); this.SuspendLayout(); @@ -407,7 +410,7 @@ namespace Mesen.GUI.Forms this.mnuShowFPS}); this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed; this.mnuEmulationSpeed.Name = "mnuEmulationSpeed"; - this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22); + this.mnuEmulationSpeed.Size = new System.Drawing.Size(135, 22); this.mnuEmulationSpeed.Text = "Speed"; // // mnuEmuSpeedNormal @@ -506,7 +509,7 @@ namespace Mesen.GUI.Forms this.mnuFullscreen}); this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen; this.mnuVideoScale.Name = "mnuVideoScale"; - this.mnuVideoScale.Size = new System.Drawing.Size(152, 22); + this.mnuVideoScale.Size = new System.Drawing.Size(135, 22); this.mnuVideoScale.Text = "Video Size"; // // mnuScale1x @@ -587,7 +590,7 @@ namespace Mesen.GUI.Forms this.toolStripMenuItem19, this.mnuBilinearInterpolation}); this.mnuVideoFilter.Name = "mnuVideoFilter"; - this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22); + this.mnuVideoFilter.Size = new System.Drawing.Size(135, 22); this.mnuVideoFilter.Text = "Video Filter"; // // mnuNoneFilter @@ -722,16 +725,29 @@ namespace Mesen.GUI.Forms this.mnuSuperEagleFilter.Text = "SuperEagle"; this.mnuSuperEagleFilter.Click += new System.EventHandler(this.mnuSuperEagleFilter_Click); // + // toolStripMenuItem19 + // + this.toolStripMenuItem19.Name = "toolStripMenuItem19"; + this.toolStripMenuItem19.Size = new System.Drawing.Size(203, 6); + // + // mnuBilinearInterpolation + // + this.mnuBilinearInterpolation.CheckOnClick = true; + this.mnuBilinearInterpolation.Name = "mnuBilinearInterpolation"; + this.mnuBilinearInterpolation.Size = new System.Drawing.Size(206, 22); + this.mnuBilinearInterpolation.Text = "Use Bilinear Interpolation"; + this.mnuBilinearInterpolation.Click += new System.EventHandler(this.mnuBilinearInterpolation_Click); + // // toolStripMenuItem10 // this.toolStripMenuItem10.Name = "toolStripMenuItem10"; - this.toolStripMenuItem10.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem10.Size = new System.Drawing.Size(132, 6); // // mnuAudioConfig // this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio; this.mnuAudioConfig.Name = "mnuAudioConfig"; - this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22); + this.mnuAudioConfig.Size = new System.Drawing.Size(135, 22); this.mnuAudioConfig.Text = "Audio"; this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click); // @@ -739,7 +755,7 @@ namespace Mesen.GUI.Forms // this.mnuInput.Image = global::Mesen.GUI.Properties.Resources.Controller; this.mnuInput.Name = "mnuInput"; - this.mnuInput.Size = new System.Drawing.Size(152, 22); + this.mnuInput.Size = new System.Drawing.Size(135, 22); this.mnuInput.Text = "Input"; this.mnuInput.Click += new System.EventHandler(this.mnuInput_Click); // @@ -752,7 +768,7 @@ namespace Mesen.GUI.Forms this.mnuRegionDendy}); this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.Globe; this.mnuRegion.Name = "mnuRegion"; - this.mnuRegion.Size = new System.Drawing.Size(152, 22); + this.mnuRegion.Size = new System.Drawing.Size(135, 22); this.mnuRegion.Text = "Region"; // // mnuRegionAuto @@ -787,20 +803,20 @@ namespace Mesen.GUI.Forms // this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.Video; this.mnuVideoConfig.Name = "mnuVideoConfig"; - this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22); + this.mnuVideoConfig.Size = new System.Drawing.Size(135, 22); this.mnuVideoConfig.Text = "Video"; this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click); // // toolStripMenuItem11 // this.toolStripMenuItem11.Name = "toolStripMenuItem11"; - this.toolStripMenuItem11.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem11.Size = new System.Drawing.Size(132, 6); // // mnuPreferences // this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Cog; this.mnuPreferences.Name = "mnuPreferences"; - this.mnuPreferences.Size = new System.Drawing.Size(152, 22); + this.mnuPreferences.Size = new System.Drawing.Size(135, 22); this.mnuPreferences.Text = "Preferences"; this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click); // @@ -809,6 +825,7 @@ namespace Mesen.GUI.Forms this.mnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuNetPlay, this.mnuMovies, + this.mnuSoundRecorder, this.mnuCheats, this.toolStripMenuItem12, this.mnuTests, @@ -933,6 +950,7 @@ namespace Mesen.GUI.Forms // // mnuPlayMovie // + this.mnuPlayMovie.Image = global::Mesen.GUI.Properties.Resources.Play; this.mnuPlayMovie.Name = "mnuPlayMovie"; this.mnuPlayMovie.Size = new System.Drawing.Size(149, 22); this.mnuPlayMovie.Text = "Play..."; @@ -943,6 +961,7 @@ namespace Mesen.GUI.Forms this.mnuRecordFrom.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuRecordFromStart, this.mnuRecordFromNow}); + this.mnuRecordFrom.Image = global::Mesen.GUI.Properties.Resources.Record; this.mnuRecordFrom.Name = "mnuRecordFrom"; this.mnuRecordFrom.Size = new System.Drawing.Size(149, 22); this.mnuRecordFrom.Text = "Record from..."; @@ -963,11 +982,38 @@ namespace Mesen.GUI.Forms // // mnuStopMovie // + this.mnuStopMovie.Image = global::Mesen.GUI.Properties.Resources.Stop; this.mnuStopMovie.Name = "mnuStopMovie"; this.mnuStopMovie.Size = new System.Drawing.Size(149, 22); this.mnuStopMovie.Text = "Stop"; this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click); // + // mnuSoundRecorder + // + this.mnuSoundRecorder.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuWaveRecord, + this.mnuWaveStop}); + this.mnuSoundRecorder.Image = global::Mesen.GUI.Properties.Resources.Microphone; + this.mnuSoundRecorder.Name = "mnuSoundRecorder"; + this.mnuSoundRecorder.Size = new System.Drawing.Size(185, 22); + this.mnuSoundRecorder.Text = "Sound Recorder"; + // + // mnuWaveRecord + // + this.mnuWaveRecord.Image = global::Mesen.GUI.Properties.Resources.Record; + this.mnuWaveRecord.Name = "mnuWaveRecord"; + this.mnuWaveRecord.Size = new System.Drawing.Size(155, 22); + this.mnuWaveRecord.Text = "Record..."; + this.mnuWaveRecord.Click += new System.EventHandler(this.mnuWaveRecord_Click); + // + // mnuWaveStop + // + this.mnuWaveStop.Image = global::Mesen.GUI.Properties.Resources.Stop; + this.mnuWaveStop.Name = "mnuWaveStop"; + this.mnuWaveStop.Size = new System.Drawing.Size(155, 22); + this.mnuWaveStop.Text = "Stop Recording"; + this.mnuWaveStop.Click += new System.EventHandler(this.mnuWaveStop_Click); + // // mnuCheats // this.mnuCheats.Name = "mnuCheats"; @@ -1105,19 +1151,6 @@ namespace Mesen.GUI.Forms this.mnuAbout.Text = "About"; this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click); // - // toolStripMenuItem19 - // - this.toolStripMenuItem19.Name = "toolStripMenuItem19"; - this.toolStripMenuItem19.Size = new System.Drawing.Size(203, 6); - // - // mnuBilinearInterpolation - // - this.mnuBilinearInterpolation.CheckOnClick = true; - this.mnuBilinearInterpolation.Name = "mnuBilinearInterpolation"; - this.mnuBilinearInterpolation.Size = new System.Drawing.Size(206, 22); - this.mnuBilinearInterpolation.Text = "Use Bilinear Interpolation"; - this.mnuBilinearInterpolation.Click += new System.EventHandler(this.mnuBilinearInterpolation_Click); - // // frmMain // this.AllowDrop = true; @@ -1263,6 +1296,9 @@ namespace Mesen.GUI.Forms private System.Windows.Forms.ToolStripMenuItem mnuSuperEagleFilter; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem19; private System.Windows.Forms.ToolStripMenuItem mnuBilinearInterpolation; + private System.Windows.Forms.ToolStripMenuItem mnuSoundRecorder; + private System.Windows.Forms.ToolStripMenuItem mnuWaveRecord; + private System.Windows.Forms.ToolStripMenuItem mnuWaveStop; } } diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index 49dfbd38..5089c2d6 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -516,6 +516,10 @@ namespace Mesen.GUI.Forms mnuRecordFromStart.Enabled = _emuThread != null && !isNetPlayClient && !moviePlaying && !movieRecording; mnuRecordFromNow.Enabled = _emuThread != null && !moviePlaying && !movieRecording; + bool waveRecording = InteropEmu.WaveIsRecording(); + mnuWaveRecord.Enabled = _emuThread != null && !waveRecording; + mnuWaveStop.Enabled = _emuThread != null && waveRecording; + bool testRecording = InteropEmu.RomTestRecording(); mnuTestRun.Enabled = !netPlay && !moviePlaying && !movieRecording; mnuTestStopRecording.Enabled = _emuThread != null && testRecording; @@ -782,6 +786,23 @@ namespace Mesen.GUI.Forms RecordMovie(false); } + + private void mnuWaveRecord_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.Filter = ResourceHelper.GetMessage("FilterWave"); + sfd.InitialDirectory = ConfigManager.WaveFolder; + sfd.FileName = Path.GetFileNameWithoutExtension(InteropEmu.GetROMPath()) + ".wav"; + if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { + InteropEmu.WaveRecord(sfd.FileName); + } + } + + private void mnuWaveStop_Click(object sender, EventArgs e) + { + InteropEmu.WaveStop(); + } + private void mnuTestRun_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index ab6187e0..3c330ca0 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -684,6 +684,8 @@ Always + + diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index a04f8fbb..e19db907 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -75,6 +75,10 @@ namespace Mesen.GUI [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MoviePlaying(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MovieRecording(); + [DllImport(DLLPath)] public static extern void WaveRecord([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename); + [DllImport(DLLPath)] public static extern void WaveStop(); + [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool WaveIsRecording(); + [DllImport(DLLPath)] public static extern Int32 RomTestRun([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename); [DllImport(DLLPath)] public static extern void RomTestRecord([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename, [MarshalAs(UnmanagedType.I1)]bool reset); [DllImport(DLLPath)] public static extern void RomTestRecordFromMovie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string testFilename, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string movieFilename); diff --git a/GUI.NET/Properties/Resources.Designer.cs b/GUI.NET/Properties/Resources.Designer.cs index a0cfc8b8..eef9863b 100644 --- a/GUI.NET/Properties/Resources.Designer.cs +++ b/GUI.NET/Properties/Resources.Designer.cs @@ -240,6 +240,16 @@ namespace Mesen.GUI.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Microphone { + get { + object obj = ResourceManager.GetObject("Microphone", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -300,6 +310,16 @@ namespace Mesen.GUI.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Record { + get { + object obj = ResourceManager.GetObject("Record", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/GUI.NET/Properties/Resources.resx b/GUI.NET/Properties/Resources.resx index 1c6c24a5..945f0bbd 100644 --- a/GUI.NET/Properties/Resources.resx +++ b/GUI.NET/Properties/Resources.resx @@ -205,4 +205,10 @@ ..\Resources\DownArrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\microphone.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Record.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/GUI.NET/Resources/Record.png b/GUI.NET/Resources/Record.png new file mode 100644 index 00000000..9e153416 Binary files /dev/null and b/GUI.NET/Resources/Record.png differ diff --git a/GUI.NET/Resources/microphone.png b/GUI.NET/Resources/microphone.png new file mode 100644 index 00000000..12db59eb Binary files /dev/null and b/GUI.NET/Resources/microphone.png differ diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 3251ebb3..5a17d24e 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -15,6 +15,7 @@ #include "../Core/AutoRomTest.h" #include "../Core/FDS.h" #include "../Core/VsControlManager.h" +#include "../Core/SoundMixer.h" NES::Renderer *_renderer = nullptr; SoundManager *_soundManager = nullptr; @@ -205,6 +206,10 @@ namespace InteropEmu { DllExport bool __stdcall MoviePlaying() { return Movie::Playing(); } DllExport bool __stdcall MovieRecording() { return Movie::Recording(); } + DllExport void __stdcall WaveRecord(char* filename) { SoundMixer::StartRecording(filename); } + DllExport void __stdcall WaveStop() { SoundMixer::StopRecording(); } + DllExport bool __stdcall WaveIsRecording() { return SoundMixer::IsRecording(); } + DllExport int32_t __stdcall RomTestRun(char* filename) { AutoRomTest romTest;