1 /* Copyright 2005 Guillaume Duhamel
2 Copyright 2005-2006, 2013 Theo Berkau
3 Copyright 2008 Filipe Azevedo <pasnox@gmail.com>
4
5 This file is part of Yabause.
6
7 Yabause is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Yabause is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Yabause; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 #include "YabauseThread.h"
22 #include "Settings.h"
23 #include "VolatileSettings.h"
24 #include "ui/UIPortManager.h"
25 #include "ui/UIYabause.h"
26
27 #include "../peripheral.h"
28
29 #include <QDateTime>
30 #include <QStringList>
31 #include <QDebug>
32 #include <QFile>
33
YabauseThread(QObject * o)34 YabauseThread::YabauseThread( QObject* o )
35 : QObject( o )
36 {
37 mPause = true;
38 mTimerId = -1;
39 mInit = -1;
40 memset(&mYabauseConf, 0, sizeof(mYabauseConf));
41 showFPS = false;
42 }
43
~YabauseThread()44 YabauseThread::~YabauseThread()
45 {
46 deInitEmulation();
47 }
48
yabauseConf()49 yabauseinit_struct* YabauseThread::yabauseConf()
50 {
51 return &mYabauseConf;
52 }
53
initEmulation()54 void YabauseThread::initEmulation()
55 {
56 reloadSettings();
57 mInit = YabauseInit( &mYabauseConf );
58 #ifdef HAVE_LIBGL
59 if (mInit == -1)
60 {
61 VideoDisableGL();
62 emit disableGL();
63 mInit = YabauseInit( &mYabauseConf );
64 }
65 #endif
66 SetOSDToggle(showFPS);
67 }
68
deInitEmulation()69 void YabauseThread::deInitEmulation()
70 {
71 YabauseDeInit();
72 mInit = -1;
73 }
74
pauseEmulation(bool pause,bool reset)75 bool YabauseThread::pauseEmulation( bool pause, bool reset )
76 {
77 if ( mPause == pause && !reset ) {
78 return true;
79 }
80
81 if ( mInit == 0 && reset ) {
82 deInitEmulation();
83 }
84
85 if ( mInit < 0 ) {
86 initEmulation();
87 }
88
89 if ( mInit < 0 )
90 {
91 emit error( QtYabause::translate( "Can't initialize Yabause" ), false );
92 return false;
93 }
94
95 mPause = pause;
96
97 if ( mPause ) {
98 ScspMuteAudio(SCSP_MUTE_SYSTEM);
99 killTimer( mTimerId );
100 mTimerId = -1;
101 }
102 else {
103 ScspUnMuteAudio(SCSP_MUTE_SYSTEM);
104 mTimerId = startTimer( 0 );
105 }
106
107 VolatileSettings * vs = QtYabause::volatileSettings();
108
109 if (vs->value("autostart").toBool())
110 {
111 if (vs->value("autostart/binary").toBool()) {
112 MappedMemoryLoadExec(
113 vs->value("autostart/binary/filename").toString().toLocal8Bit().constData(),
114 vs->value("autostart/binary/address").toUInt());
115 }
116 else if (vs->value("autostart/load").toBool()) {
117 YabLoadStateSlot( QFile::encodeName( QtYabause::volatileSettings()->value( "General/SaveStates", getDataDirPath() ).toString() ).constData(), vs->value("autostart/load/slot").toInt() );
118 }
119 vs->setValue("autostart", false);
120 }
121
122 emit this->pause( mPause );
123
124 return true;
125 }
126
resetEmulation()127 bool YabauseThread::resetEmulation()
128 {
129 if ( mInit < 0 ) {
130 return false;
131 }
132
133 YabauseReset();
134
135 emit reset();
136
137 return true;
138 }
139
reloadControllers()140 void YabauseThread::reloadControllers()
141 {
142 PerPortReset();
143 QtYabause::clearPadsBits();
144
145 Settings* settings = QtYabause::settings();
146
147 emit toggleEmulateMouse( false );
148
149 for ( uint port = 1; port < 3; port++ )
150 {
151 settings->beginGroup( QString( "Input/Port/%1/Id" ).arg( port ) );
152 QStringList ids = settings->childGroups();
153 settings->endGroup();
154
155 ids.sort();
156 foreach ( const QString& id, ids )
157 {
158 uint type = settings->value( QString( UIPortManager::mSettingsType ).arg( port ).arg( id ) ).toUInt();
159
160 switch ( type )
161 {
162 case PERVIRTUALON:
163 case PERPAD:
164 {
165 PerPad_struct* padbits = PerPadAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
166
167 settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
168 QStringList padKeys = settings->childKeys();
169 settings->endGroup();
170
171 padKeys.sort();
172 foreach ( const QString& padKey, padKeys )
173 {
174 const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( padKey ) ).toString();
175
176 PerSetKey( key.toUInt(), padKey.toUInt(), padbits );
177 }
178 break;
179 }
180 case PERWHEEL:
181 {
182 PerAnalog_struct* analogbits = PerWheelAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
183
184 settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
185 QStringList analogKeys = settings->childKeys();
186 settings->endGroup();
187
188 analogKeys.sort();
189 foreach(const QString& analogKey, analogKeys)
190 {
191 const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
192
193 PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
194 }
195 break;
196 }
197 case PERMISSIONSTICK:
198 {
199 PerAnalog_struct* analogbits = PerMissionStickAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
200
201 settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
202 QStringList analogKeys = settings->childKeys();
203 settings->endGroup();
204
205 analogKeys.sort();
206 foreach(const QString& analogKey, analogKeys)
207 {
208 const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
209
210 PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
211 }
212 break;
213 }
214 case PERTWINSTICKS:
215 {
216 PerAnalog_struct* analogbits = PerTwinSticksAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
217
218 settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
219 QStringList analogKeys = settings->childKeys();
220 settings->endGroup();
221
222 analogKeys.sort();
223 foreach(const QString& analogKey, analogKeys)
224 {
225 const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
226
227 PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
228 }
229 break;
230 }
231 case PER3DPAD:
232 {
233 PerAnalog_struct* analogbits = Per3DPadAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
234
235 settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
236 QStringList analogKeys = settings->childKeys();
237 settings->endGroup();
238
239 analogKeys.sort();
240 foreach ( const QString& analogKey, analogKeys )
241 {
242 const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( analogKey ) ).toString();
243
244 PerSetKey( key.toUInt(), analogKey.toUInt(), analogbits );
245 }
246 break;
247 }
248 case PERGUN:
249 {
250 PerGun_struct* gunbits = PerGunAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
251 settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
252 QStringList gunKeys = settings->childKeys();
253 settings->endGroup();
254
255 gunKeys.sort();
256 foreach ( const QString& gunKey, gunKeys )
257 {
258 const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( gunKey ) ).toString();
259
260 PerSetKey( key.toUInt(), gunKey.toUInt(), gunbits );
261 }
262 break;
263 }
264 case PERKEYBOARD:
265 QtYabause::mainWindow()->appendLog( "Keyboard controller type is not yet supported" );
266 break;
267 case PERMOUSE:
268 {
269 PerMouse_struct* mousebits = PerMouseAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
270
271 settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
272 QStringList mouseKeys = settings->childKeys();
273 settings->endGroup();
274
275 mouseKeys.sort();
276 foreach ( const QString& mouseKey, mouseKeys )
277 {
278 const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( mouseKey ) ).toString();
279
280 PerSetKey( key.toUInt(), mouseKey.toUInt(), mousebits );
281 }
282
283 emit toggleEmulateMouse( true );
284 break;
285 }
286 case 0:
287 // Unconnected
288 break;
289 default:
290 QtYabause::mainWindow()->appendLog( "Invalid controller type" );
291 break;
292 }
293 }
294 }
295 }
296
localtime_qt(const QDateTime & input,struct tm * result)297 static struct tm *localtime_qt(const QDateTime &input, struct tm *result)
298 {
299 QDate date(input.date());
300 result->tm_year = date.year() - 1900;
301 result->tm_mon = date.month();
302 result->tm_mday = date.day();
303 result->tm_wday = date.dayOfWeek();
304 result->tm_yday = date.dayOfYear();
305
306 QTime time(input.time());
307 result->tm_sec = time.second();
308 result->tm_min = time.minute();
309 result->tm_hour = time.hour();
310
311 return result;
312 }
313
reloadClock()314 void YabauseThread::reloadClock()
315 {
316 QString tmp;
317 Settings* s = QtYabause::settings();
318
319 if (mYabauseConf.basetime == 0)
320 tmp = "";
321 else
322 tmp = QDateTime::fromTime_t(mYabauseConf.basetime).toString();
323
324 // Clock sync
325 mYabauseConf.clocksync = (int)s->value( "General/ClockSync", mYabauseConf.clocksync ).toBool();
326 tmp = s->value( "General/FixedBaseTime", tmp ).toString();
327 if (!tmp.isEmpty() && mYabauseConf.clocksync)
328 {
329 QDateTime date = QDateTime::fromString(tmp, Qt::ISODate);
330 mYabauseConf.basetime = (long)date.toTime_t();
331 }
332 else {
333 mYabauseConf.basetime = 0;
334 }
335 }
336
reloadSettings()337 void YabauseThread::reloadSettings()
338 {
339 //QMutexLocker l( &mMutex );
340 // get settings pointer
341 VolatileSettings* vs = QtYabause::volatileSettings();
342
343 // reset yabause conf
344 resetYabauseConf();
345
346 // read & apply settings
347 mYabauseConf.m68kcoretype = vs->value("Advanced/68kCore", mYabauseConf.m68kcoretype).toInt();
348 mYabauseConf.percoretype = vs->value( "Input/PerCore", mYabauseConf.percoretype ).toInt();
349 mYabauseConf.sh1coretype = vs->value( "Advanced/SH1Interpreter", mYabauseConf.sh1coretype ).toInt();
350 mYabauseConf.use_cd_block_lle = vs->value( "Advanced/EnableCDBlockLLE", mYabauseConf.use_cd_block_lle ).toBool();
351 mYabauseConf.use_sh2_dma_timing = vs->value("Advanced/EnableSh2DmaTiming", mYabauseConf.use_sh2_dma_timing).toBool();
352 mYabauseConf.use_scu_dma_timing = vs->value("Advanced/EnableScuDmaTiming", mYabauseConf.use_scu_dma_timing).toBool();
353 mYabauseConf.sh2_cache_enabled = vs->value("Advanced/EnableSh2Cache", mYabauseConf.sh2_cache_enabled).toBool();
354 mYabauseConf.sh2coretype = vs->value( "Advanced/SH2Interpreter", mYabauseConf.sh2coretype ).toInt();
355 mYabauseConf.vidcoretype = vs->value( "Video/VideoCore", mYabauseConf.vidcoretype ).toInt();
356 mYabauseConf.osdcoretype = vs->value( "Video/OSDCore", mYabauseConf.osdcoretype ).toInt();
357 mYabauseConf.sndcoretype = vs->value( "Sound/SoundCore", mYabauseConf.sndcoretype ).toInt();
358 mYabauseConf.cdcoretype = vs->value( "General/CdRom", mYabauseConf.cdcoretype ).toInt();
359 mYabauseConf.carttype = vs->value( "Cartridge/Type", mYabauseConf.carttype ).toInt();
360 const QString r = vs->value( "Advanced/Region", mYabauseConf.regionid ).toString();
361 if ( r.isEmpty() || r == "Auto" )
362 mYabauseConf.regionid = 0;
363 else
364 {
365 switch ( r[0].toLatin1() )
366 {
367 case 'J': mYabauseConf.regionid = 1; break;
368 case 'T': mYabauseConf.regionid = 2; break;
369 case 'U': mYabauseConf.regionid = 4; break;
370 case 'B': mYabauseConf.regionid = 5; break;
371 case 'K': mYabauseConf.regionid = 6; break;
372 case 'A': mYabauseConf.regionid = 0xA; break;
373 case 'E': mYabauseConf.regionid = 0xC; break;
374 case 'L': mYabauseConf.regionid = 0xD; break;
375 }
376 }
377 if (vs->value("General/EnableEmulatedBios", false).toBool())
378 mYabauseConf.biospath = strdup( "" );
379 else
380 mYabauseConf.biospath = strdup( QFile::encodeName( vs->value( "General/Bios", mYabauseConf.biospath ).toString()).constData() );
381
382 mYabauseConf.cdpath = strdup( QFile::encodeName( vs->value( "General/CdRomISO", mYabauseConf.cdpath ).toString()).constData());
383 mYabauseConf.ssfpath = strdup( QFile::encodeName( vs->value("General/SSFPath", mYabauseConf.ssfpath).toString()).constData());
384 mYabauseConf.play_ssf = vs->value("General/PlaySSF", false).toBool();
385 showFPS = vs->value( "General/ShowFPS", false ).toBool();
386 mYabauseConf.usethreads = (int)vs->value( "General/EnableMultiThreading", mYabauseConf.usethreads ).toBool();
387 mYabauseConf.numthreads = vs->value( "General/NumThreads", mYabauseConf.numthreads ).toInt();
388 mYabauseConf.buppath = strdup( QFile::encodeName( vs->value( "Memory/Path", mYabauseConf.buppath ).toString()).constData() );
389 mYabauseConf.sh1rompath = strdup( QFile::encodeName( vs->value( "SH1ROM/Path", mYabauseConf.mpegpath ).toString()).constData() );
390 mYabauseConf.mpegpath = strdup( QFile::encodeName( vs->value( "MpegROM/Path", mYabauseConf.mpegpath ).toString()).constData() );
391 mYabauseConf.cartpath = strdup( QFile::encodeName( vs->value( "Cartridge/Path", mYabauseConf.cartpath ).toString()).constData() );
392 mYabauseConf.modemip = strdup( vs->value( "Cartridge/ModemIP", mYabauseConf.modemip ).toString().toLatin1().constData() );
393 mYabauseConf.modemport = strdup( vs->value( "Cartridge/ModemPort", mYabauseConf.modemport ).toString().toLatin1().constData() );
394 mYabauseConf.videoformattype = vs->value( "Video/VideoFormat", mYabauseConf.videoformattype ).toInt();
395 mYabauseConf.use_new_scsp = (int)vs->value("Sound/NewScsp", mYabauseConf.use_new_scsp).toBool();
396 mYabauseConf.use_scsp_dsp_dynarec = (int)vs->value("Sound/EnableScspDspDynarec", mYabauseConf.use_scsp_dsp_dynarec).toBool();
397 mYabauseConf.use_scu_dsp_jit = (int)vs->value("Advanced/EnableScuDspDynarec", mYabauseConf.use_scu_dsp_jit).toBool();
398
399 emit requestSize( QSize( vs->value( "Video/WinWidth", 0 ).toInt(), vs->value( "Video/WinHeight", 0 ).toInt() ) );
400 emit requestFullscreen( vs->value( "Video/Fullscreen", false ).toBool() );
401 emit requestVolumeChange( vs->value( "Sound/Volume", 100 ).toInt() );
402
403 reloadClock();
404 reloadControllers();
405 }
406
emulationRunning()407 bool YabauseThread::emulationRunning()
408 {
409 //QMutexLocker l( &mMutex );
410 return mTimerId != -1 && !mPause;
411 }
412
emulationPaused()413 bool YabauseThread::emulationPaused()
414 {
415 //QMutexLocker l( &mMutex );
416 return mPause;
417 }
418
resetYabauseConf()419 void YabauseThread::resetYabauseConf()
420 {
421 // free structure
422 memset( &mYabauseConf, 0, sizeof( yabauseinit_struct ) );
423 // fill default structure
424 mYabauseConf.m68kcoretype = M68KCORE_MUSASHI;
425 mYabauseConf.percoretype = QtYabause::defaultPERCore().id;
426 mYabauseConf.sh1coretype = SH2CORE_DEFAULT;
427 mYabauseConf.use_cd_block_lle = 0;
428 mYabauseConf.sh2coretype = SH2CORE_DEFAULT;
429 mYabauseConf.vidcoretype = QtYabause::defaultVIDCore().id;
430 mYabauseConf.sndcoretype = QtYabause::defaultSNDCore().id;
431 mYabauseConf.cdcoretype = QtYabause::defaultCDCore().id;
432 mYabauseConf.carttype = CART_NONE;
433 mYabauseConf.regionid = 0;
434 mYabauseConf.biospath = 0;
435 mYabauseConf.cdpath = 0;
436 mYabauseConf.buppath = 0;
437 mYabauseConf.mpegpath = 0;
438 mYabauseConf.cartpath = 0;
439 mYabauseConf.videoformattype = VIDEOFORMATTYPE_NTSC;
440 mYabauseConf.skip_load = 0;
441 int numThreads = QThread::idealThreadCount();
442 mYabauseConf.usethreads = numThreads <= 1 ? 0 : 1;
443 mYabauseConf.numthreads = numThreads < 0 ? 1 : numThreads;
444 }
445
timerEvent(QTimerEvent *)446 void YabauseThread::timerEvent( QTimerEvent* )
447 {
448 //mPause = true;
449 //mRunning = true;
450 //while ( mRunning )
451 {
452 if ( !mPause )
453 PERCore->HandleEvents();
454 //else
455 //msleep( 25 );
456 //sleep( 0 );
457 }
458 }
459