1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #include "NstResourceString.hpp" 26 #include "NstIoScreen.hpp" 27 #include "NstWindowParam.hpp" 28 #include "NstWindowUser.hpp" 29 #include "NstManager.hpp" 30 #include "NstDialogSound.hpp" 31 #include "NstManagerSound.hpp" 32 #include "NstManagerSoundRecorder.hpp" 33 34 namespace Nestopia 35 { 36 namespace Managers 37 { Recorder(Window::Menu & m,Window::Sound::Recorder & d,Emulator & e)38 Sound::Recorder::Recorder 39 ( 40 Window::Menu& m, 41 Window::Sound::Recorder& d, 42 Emulator& e 43 ) 44 : 45 Manager ( e, m, this, &Recorder::OnEmuEvent ), 46 recording ( false ), 47 file ( Io::Wave::MODE_WRITE ), 48 dialog ( d ) 49 { 50 static const Window::Menu::CmdHandler::Entry<Recorder> commands[] = 51 { 52 { IDM_FILE_SOUND_RECORDER_FILE, &Recorder::OnCmdFile }, 53 { IDM_FILE_SOUND_RECORDER_START, &Recorder::OnCmdRecord }, 54 { IDM_FILE_SOUND_RECORDER_STOP, &Recorder::OnCmdStop }, 55 { IDM_FILE_SOUND_RECORDER_REWIND, &Recorder::OnCmdRewind } 56 }; 57 58 menu.Commands().Add( this, commands ); 59 60 static const Window::Menu::PopupHandler::Entry<Recorder> popups[] = 61 { 62 { Window::Menu::PopupHandler::Pos<IDM_POS_FILE,IDM_POS_FILE_SOUNDRECORDER>::ID, &Recorder::OnMenu } 63 }; 64 65 menu.Popups().Add( this, popups ); 66 } 67 ~Recorder()68 Sound::Recorder::~Recorder() 69 { 70 } 71 CanRecord() const72 bool Sound::Recorder::CanRecord() const 73 { 74 return 75 ( 76 !recording && 77 dialog.WaveFile().Length() && 78 waveFormat.nSamplesPerSec && 79 waveFormat.wBitsPerSample && 80 !emulator.NetPlayers() && 81 emulator.IsOn() 82 ); 83 } 84 CanRewind() const85 bool Sound::Recorder::CanRewind() const 86 { 87 return !recording && file.IsOpen(); 88 } 89 CanStop() const90 bool Sound::Recorder::CanStop() const 91 { 92 return recording; 93 } 94 Close()95 void Sound::Recorder::Close() 96 { 97 recording = false; 98 99 try 100 { 101 file.Close(); 102 } 103 catch (Io::Wave::Exception id) 104 { 105 Window::User::Fail( id ); 106 } 107 } 108 Enable(const WAVEFORMATEX * newWaveFormat)109 void Sound::Recorder::Enable(const WAVEFORMATEX* newWaveFormat) 110 { 111 if (newWaveFormat) 112 { 113 if (waveFormat == *newWaveFormat) 114 return; 115 116 waveFormat = *newWaveFormat; 117 } 118 else 119 { 120 waveFormat.Clear(); 121 } 122 123 Close(); 124 } 125 OnMenu(const Window::Menu::PopupHandler::Param & param)126 void Sound::Recorder::OnMenu(const Window::Menu::PopupHandler::Param& param) 127 { 128 menu[ IDM_FILE_SOUND_RECORDER_START ].Enable( !param.show || CanRecord() ); 129 menu[ IDM_FILE_SOUND_RECORDER_STOP ].Enable( !param.show || CanStop() ); 130 menu[ IDM_FILE_SOUND_RECORDER_REWIND ].Enable( !param.show || CanRewind() ); 131 } 132 OnEmuEvent(const Emulator::Event event,const Emulator::Data data)133 void Sound::Recorder::OnEmuEvent(const Emulator::Event event,const Emulator::Data data) 134 { 135 switch (event) 136 { 137 case Emulator::EVENT_POWER_OFF: 138 139 recording = false; 140 break; 141 142 case Emulator::EVENT_NETPLAY_MODE: 143 144 menu[IDM_POS_FILE][IDM_POS_FILE_SOUNDRECORDER].Enable( !data ); 145 break; 146 } 147 } 148 OnCmdFile(uint)149 void Sound::Recorder::OnCmdFile(uint) 150 { 151 dialog.Open(); 152 153 if (file.IsOpen() && file.GetName() != dialog.WaveFile()) 154 Close(); 155 } 156 OnCmdRecord(uint)157 void Sound::Recorder::OnCmdRecord(uint) 158 { 159 if (CanRecord()) 160 { 161 if (!file.IsOpen()) 162 { 163 try 164 { 165 file.Open( dialog.WaveFile(), waveFormat ); 166 } 167 catch (Io::Wave::Exception id) 168 { 169 Window::User::Fail( id ); 170 return; 171 } 172 173 size = 0; 174 nextSmallSizeNotification = SMALL_SIZE; 175 nextBigSizeNotification = BIG_SIZE; 176 } 177 178 Io::Screen() << Resource::String(size ? IDS_SCREEN_SOUND_RECORDER_RESUME : IDS_SCREEN_SOUND_RECORDER_START); 179 180 recording = true; 181 Resume(); 182 } 183 } 184 OnCmdStop(uint)185 void Sound::Recorder::OnCmdStop(uint) 186 { 187 if (CanStop()) 188 { 189 Io::Screen() << Resource::String(IDS_SCREEN_SOUND_RECORDER_STOP); 190 191 recording = false; 192 Resume(); 193 } 194 } 195 OnCmdRewind(uint)196 void Sound::Recorder::OnCmdRewind(uint) 197 { 198 if (CanRewind()) 199 { 200 try 201 { 202 file.Close(); 203 } 204 catch (Io::Wave::Exception id) 205 { 206 Window::User::Fail( id ); 207 } 208 209 Resume(); 210 } 211 } 212 Flush(const Nes::Sound::Output & output)213 void Sound::Recorder::Flush(const Nes::Sound::Output& output) 214 { 215 if (recording) 216 { 217 NST_VERIFY( file.IsOpen() ); 218 219 try 220 { 221 for (uint i=0; i < 2; ++i) 222 file.Write( output.samples[i], output.length[i] * waveFormat.nBlockAlign ); 223 } 224 catch (Io::Wave::Exception ids) 225 { 226 recording = false; 227 Window::User::Fail( ids ); 228 return; 229 } 230 231 size += output.length[0] + output.length[1]; 232 233 if (size >= nextBigSizeNotification) 234 { 235 nextBigSizeNotification += BIG_SIZE; 236 Window::User::Inform( IDS_WAVE_WARN_FILE_BIG ); 237 } 238 else if (size >= nextSmallSizeNotification) 239 { 240 Io::Screen() << Resource::String(IDS_SCREEN_SOUND_RECORDER_WRITTEN).Invoke( HeapString() << (nextSmallSizeNotification / ONE_MB) ); 241 nextSmallSizeNotification += SMALL_SIZE; 242 } 243 } 244 } 245 } 246 } 247