Sound Recorder: Added .wav recording feature (Tools menu)

This commit is contained in:
Souryo 2016-06-05 14:36:20 -04:00
parent 956834d4a5
commit c5d1e4cfc7
22 changed files with 350 additions and 73 deletions

View File

@ -23,6 +23,7 @@ Console::Console()
Console::~Console()
{
Movie::Stop();
SoundMixer::StopRecording();
}
shared_ptr<Console> 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();

View File

@ -185,6 +185,7 @@
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -213,6 +214,7 @@
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -551,6 +553,7 @@
<ClInclude Include="VsControlManager.h" />
<ClInclude Include="VsSystem.h" />
<ClInclude Include="ScaleFilter.h" />
<ClInclude Include="WaveRecorder.h" />
<ClInclude Include="Zapper.h" />
</ItemGroup>
<ItemGroup>
@ -611,6 +614,7 @@
<ClCompile Include="BaseVideoFilter.cpp" />
<ClCompile Include="VsControlManager.cpp" />
<ClCompile Include="ScaleFilter.cpp" />
<ClCompile Include="WaveRecorder.cpp" />
<ClCompile Include="Zapper.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Debugger">
<UniqueIdentifier>{ff3c6e48-3987-41d2-8916-b588a457ff30}</UniqueIdentifier>
</Filter>
@ -72,11 +64,12 @@
<Filter Include="Nes\Mappers\Taito">
<UniqueIdentifier>{1d706c9e-639f-4da0-a7ce-50d04b2b6a7e}</UniqueIdentifier>
</Filter>
<Filter Include="Misc">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IAudioDevice.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
@ -101,9 +94,6 @@
<ClInclude Include="ColorDreams.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="Movie.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IMessageManager.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
@ -149,12 +139,6 @@
<ClInclude Include="Breakpoint.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="SaveStateManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MessageManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IKeyManager.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
@ -185,9 +169,6 @@
<ClInclude Include="DeltaModulationChannel.h">
<Filter>Nes\APU</Filter>
</ClInclude>
<ClInclude Include="EmulationSettings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BF909x.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
@ -203,9 +184,6 @@
<ClInclude Include="IRenderingDevice.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
<ClInclude Include="AutoRomTest.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CpRom.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
@ -314,15 +292,9 @@
<ClInclude Include="BaseMapper.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="TxSRom.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VRC6.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="VRC1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VrcIrq.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
@ -590,13 +562,40 @@
<ClInclude Include="Snapshotable.h">
<Filter>Nes</Filter>
</ClInclude>
<ClInclude Include="AutoRomTest.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="EmulationSettings.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="MessageManager.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="Movie.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="SaveStateManager.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="VRC1.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="TxSRom.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="WaveRecorder.h">
<Filter>Misc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="Movie.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="Debugger.cpp">
<Filter>Debugger</Filter>
@ -611,19 +610,19 @@
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="SaveStateManager.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="MessageManager.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="EmulationSettings.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="CodeDataLogger.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="AutoRomTest.cpp">
<Filter>Source Files</Filter>
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="BaseVideoFilter.cpp">
<Filter>VideoDecoder</Filter>
@ -739,5 +738,8 @@
<ClCompile Include="Snapshotable.cpp">
<Filter>Nes</Filter>
</ClCompile>
<ClCompile Include="WaveRecorder.cpp">
<Filter>Misc</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -15,6 +15,7 @@ std::unordered_map<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> 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<string, string> MessageManager::_jaResources = {
{ "NetPlay", u8"ネットプレー" },
{ "SaveStates", u8"クイックセーブ" },
{ "ScreenshotSaved", u8"スクリーンショット" },
{ "SoundRecorder", u8"サウンドレコーダー" },
{ "Test", u8"テスト" },
{ "CheatApplied", u8"チートコード%1個を有効にしました。" },
@ -157,6 +164,8 @@ std::unordered_map<string, string> 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を使うゲームはロードできません。" },

View File

@ -4,6 +4,8 @@
#include "CPU.h"
IAudioDevice* SoundMixer::AudioDevice = nullptr;
unique_ptr<WaveRecorder> 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;
}

View File

@ -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> _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);
};

85
Core/WaveRecorder.cpp Normal file
View File

@ -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);
}
}

21
Core/WaveRecorder.h Normal file
View File

@ -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);
};

View File

@ -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

View File

@ -3,6 +3,7 @@
<Messages>
<Message ID="FilterAll">All Files (*.*)|*.*</Message>
<Message ID="FilterMovie">Movie files (*.mmo)|*.mmo|All Files (*.*)|*.*</Message>
<Message ID="FilterWave">Wave files (*.wav)|*.wav|All Files (*.*)|*.*</Message>
<Message ID="FilterPalette">Palette Files (*.pal)|*.pal|All Files (*.*)|*.*</Message>
<Message ID="FilterRom">All supported formats (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|ZIP Archives (*.zip)|*.ZIP|All (*.*)|*.*</Message>
<Message ID="FilterRomIps">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 (*.*)|*.*</Message>

View File

@ -67,6 +67,9 @@
<Control ID="mnuRecordFromStart">Du début du jeu</Control>
<Control ID="mnuRecordFromNow">De maintenant</Control>
<Control ID="mnuStopMovie">Arrêter</Control>
<Control ID="mnuSoundRecorder">Enregistreur audio</Control>
<Control ID="mnuWaveRecord">Enregistrer...</Control>
<Control ID="mnuWaveStop">Arrêter</Control>
<Control ID="mnuCheats">Codes</Control>
<Control ID="mnuTests">Tests</Control>
<Control ID="mnuTestRun">Run...</Control>
@ -307,11 +310,12 @@
</Forms>
<Messages>
<Message ID="FilterAll">Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterMovie">Films (*.mmo)|*.mmo|All (*.*)|*.*</Message>
<Message ID="FilterPalette">Fichier de palette (*.pal)|*.pal|All Files (*.*)|*.*</Message>
<Message ID="FilterRom">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 (*.*)|*.*</Message>
<Message ID="FilterRomIps">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 (*.*)|*.*</Message>
<Message ID="FilterTest">Fichiers de test (*.mtp)|*.mtp|All (*.*)|*.*</Message>
<Message ID="FilterMovie">Films (*.mmo)|*.mmo|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterWave">Fichiers wave (*.wav)|*.wav|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterPalette">Fichier de palette (*.pal)|*.pal|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterRom">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 (*.*)|*.*</Message>
<Message ID="FilterRomIps">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 (*.*)|*.*</Message>
<Message ID="FilterTest">Fichiers de test (*.mtp)|*.mtp|Tous les fichiers (*.*)|*.*</Message>
<Message ID="Resume">Continuer</Message>
<Message ID="Pause">Pause</Message>

View File

@ -67,6 +67,9 @@
<Control ID="mnuRecordFromStart">最初から</Control>
<Control ID="mnuRecordFromNow">この時点から</Control>
<Control ID="mnuStopMovie">停止</Control>
<Control ID="mnuSoundRecorder">サウンドレコーダー</Control>
<Control ID="mnuWaveRecord">録音</Control>
<Control ID="mnuWaveStop">停止</Control>
<Control ID="mnuCheats">チートコード</Control>
<Control ID="mnuTests">テスト</Control>
<Control ID="mnuTestRun">Run...</Control>
@ -301,6 +304,7 @@
<Messages>
<Message ID="FilterAll">すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterMovie">動画 (*.mmo)|*.mmo|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterWave">WAVファイル (*.wav)|*.wav|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterPalette">パレットファイル (*.pal)|*.pal|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterRom">対応するすべてのファイル (*.nes, *.zip, *.fds)|*.NES;*.ZIP;*.FDS|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterRomIps">対応するすべてのファイル (*.nes, *.zip, *.fds, *.ips)|*.NES;*.ZIP;*.IPS;*.FDS|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|IPSファイル (*.ips)|*.IPS|すべてのファイル (*.*)|*.*</Message>

View File

@ -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;
}
}

View File

@ -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();

View File

@ -684,6 +684,8 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Icon.ico" />
<None Include="Resources\Record.png" />
<None Include="Resources\microphone.png" />
<None Include="Resources\DownArrow.png" />
<None Include="Resources\accept.png" />
<Content Include="Resources\coins.png" />

View File

@ -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);

View File

@ -240,6 +240,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Microphone {
get {
object obj = ResourceManager.GetObject("Microphone", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@ -300,6 +310,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Record {
get {
object obj = ResourceManager.GetObject("Record", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -205,4 +205,10 @@
<data name="DownArrow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DownArrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Microphone" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\microphone.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Record" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Record.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

View File

@ -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;