diff --git a/.github/README.md b/.github/README.md index 16b5665c7..710e6d205 100644 --- a/.github/README.md +++ b/.github/README.md @@ -132,6 +132,15 @@ You can use `sudo apt-get -y install $(cat AppleWin/source/linux/raspbian.list.t See [Travis](/.travis.yml) CI too. +### Windows (libretro core only) + +Build using msys2, using the standard build instructions below. + +Install the following packages (for x64 build): +``` +pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-libyaml mingw-w64-x86_64-minizip mingw-w64-x86_64-libslirp +``` + ### Building ``` diff --git a/.gitignore b/.gitignore index d11468c38..80b8f5da5 100644 --- a/.gitignore +++ b/.gitignore @@ -249,3 +249,6 @@ CMakeLists.txt.user* # VSCode .vscode + +# libretro +source/frontends/libretro/*.inl diff --git a/CMakeLists.txt b/CMakeLists.txt index 105436cfa..c3596ba58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compile_options(-Werror=format -Wno-error=format-overflow -Wno-error=format-truncation -Wno-psabi) endif() +if (BUILD_LIBRETRO) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") +endif() + MESSAGE("CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") MESSAGE("CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") MESSAGE("CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") @@ -54,7 +58,9 @@ endif() include_directories(source) add_subdirectory(source) -add_subdirectory(source/linux/libwindows) +if (NOT WIN32) + add_subdirectory(source/linux/libwindows) +endif() add_subdirectory(test/TestCPU6502) if (BUILD_LIBRETRO OR BUILD_APPLEN OR BUILD_SA2) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 3251df38f..8c39957de 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -37,8 +37,6 @@ if ("${SLIRP_FOUND}" STREQUAL "") endif() endif() -find_package(Boost REQUIRED) - set(SOURCE_FILES Tfe/tfesupp.cpp Tfe/NetworkBackend.cpp @@ -103,19 +101,13 @@ set(SOURCE_FILES FrameBase.cpp CmdLine.cpp - Configuration/PropertySheetHelper.cpp - Configuration/Config.cpp - - linux/resources.cpp - linux/benchmark.cpp + linux/context.cpp + linux/linuxframe.cpp linux/paddle.cpp - linux/version.cpp linux/registryclass.cpp - linux/linuxframe.cpp - linux/context.cpp - linux/cassettetape.cpp - linux/network/slirp2.cpp - linux/network/portfwds.cpp + linux/resources.cpp + linux/soundbuffer.cpp + linux/version.cpp linux/duplicates/Debugger_Display.cpp linux/duplicates/Debugger_Win32.cpp @@ -132,12 +124,15 @@ set(SOURCE_FILES linux/duplicates/PageSound.cpp linux/duplicates/PageDisk.cpp linux/duplicates/PageAdvanced.cpp + + Configuration/PropertySheetHelper.cpp + Configuration/Config.cpp Z80VICE/z80.cpp Z80VICE/z80mem.cpp Z80VICE/daa.cpp ) - + set(HEADER_FILES Tfe/tfearch.h Tfe/tfesupp.h @@ -218,28 +213,63 @@ set(HEADER_FILES Configuration/PropertySheetHelper.h Configuration/Config.h - linux/resources.h - linux/linuxinterface.h - linux/benchmark.h - linux/paddle.h - linux/version.h - linux/registryclass.h - linux/keyboardbuffer.h - linux/linuxframe.h - linux/cassettetape.h - linux/network/slirp2.h - linux/network/portfwds.h - Z80VICE/z80.h Z80VICE/z80mem.h Z80VICE/z80regs.h Z80VICE/daa.h ) +if(WIN32) + set(SOURCE_FILES_PLATFORM + Registry.cpp + Keyboard.cpp + Speech.cpp + Tape.cpp + ) + set(HEADER_FILES_PLATFORM + Registry.h + Keyboard.h + ) + set(EXTRA_LIBS -lwsock32 -liphlpapi -ldsound -ldxguid -lwinmm -ldinput8 -luser32 -lgdi32 -lcomctl32 -lsapi -lstrmiids) + + # force static link of dependent libraries + if(EXISTS "${YAML_LIBRARY_DIRS}/libyaml.a") + set(YAML_LIBRARIES -L${YAML_LIBRARY_DIRS};libyaml.a) + endif() + if(EXISTS "${MINIZIP_LIBRARY_DIRS}/libminizip.a") + set(MINIZIP_LIBRARIES -L${MINIZIP_LIBRARY_DIRS};libminizip.a;libz.a;libbz2.a) + endif() + if(EXISTS "${SLIRP_LIBDIR}/libslirp.a") + set(SLIRP_LIBRARIES -L${SLIRP_LIBDIR};libslirp.a;libintl.a) + endif() +else() + set(SOURCE_FILES_PLATFORM + linux/benchmark.cpp + linux/cassettetape.cpp + linux/network/slirp2.cpp + linux/network/portfwds.cpp + ) + + set(HEADER_FILES_PLATFORM + linux/resources.h + linux/benchmark.h + linux/paddle.h + linux/version.h + linux/registryclass.h + linux/keyboardbuffer.h + linux/linuxframe.h + linux/cassettetape.h + linux/network/slirp2.h + linux/network/portfwds.h + ) + + set(EXTRA_LIBS windows) +endif() + # we used to generate a shared object, but it turns out there are more cons than pros add_library(appleii STATIC - ${SOURCE_FILES} - ${HEADER_FILES} + ${SOURCE_FILES} ${SOURCE_FILES_PLATFORM} + ${HEADER_FILES} ${HEADER_FILES_PLATFORM} ) if ("${PCAP_FOUND}" STREQUAL "1") @@ -251,7 +281,6 @@ endif() target_include_directories(appleii PRIVATE ${YAML_INCLUDE_DIRS} ${PCAP_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} ${SLIRP_INCLUDE_DIRS} Debugger ) @@ -268,10 +297,8 @@ target_link_libraries(appleii PRIVATE ${PCAP_LIBRARIES} ${SLIRP_LIBRARIES} ZLIB::ZLIB - ) - -target_link_libraries(appleii PUBLIC - windows + common2 + ${EXTRA_LIBS} ) target_link_directories(appleii PRIVATE @@ -287,7 +314,8 @@ target_compile_options(appleii PUBLIC add_custom_command( TARGET appleii POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/bin/*.SYM ${CMAKE_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/bin/A2_BASIC.SYM ${CMAKE_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/bin/APPLE2E.SYM ${CMAKE_BINARY_DIR} ) configure_file(linux/config.h.in linux/config.h) diff --git a/source/Common.h b/source/Common.h index 1e3b6fba7..ef0f0ec52 100644 --- a/source/Common.h +++ b/source/Common.h @@ -140,7 +140,7 @@ enum AppMode_e #define WM_USER_FULLSCREEN WM_USER+8 #define VK_SNAPSHOT_TEXT WM_USER+9 // PrintScreen+Ctrl -#ifdef _MSC_VER +#ifdef _WIN32 #define PATH_SEPARATOR '\\' #else #define PATH_SEPARATOR '/' diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 31447d41f..04b769421 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -6538,7 +6538,9 @@ bool ParseAssemblyListing ( bool bBytesToMemory, bool bAddSymbols ) { *p = 0; // sscanf( sLine, "%s %s %s %s %s %s %s %s", sAddr1, sByte1, sByte2, sByte3, sLineN, sLabel, sAsm, sParam ); - sscanf( sLine, "%X", &nAddress ); + unsigned nScanAddress; // helper variable in case sizeof(DWORD) != sizeof(unsigned) + sscanf( sLine, "%X", &nScanAddress ); + nAddress = nScanAddress; if (nAddress >= INVALID_ADDRESS) // || (sName[0] == 0) ) continue; diff --git a/source/DiskImage.h b/source/DiskImage.h index 44e3fc912..f71b7fa88 100644 --- a/source/DiskImage.h +++ b/source/DiskImage.h @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "DiskDefs.h" -#ifdef _MSC_VER +#ifdef _WIN32 #define RAND_THRESHOLD(num, den) ((RAND_MAX * num) / den) diff --git a/source/Log.cpp b/source/Log.cpp index c1fd07596..347305819 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA FILE* g_fh = NULL; -#ifdef _MSC_VER +#ifdef _WIN32 #define LOG_FILENAME "AppleWin.log" #else // save to /tmp as otherwise it creates a file in the current folder which can be a bit everywhere @@ -49,7 +49,7 @@ inline std::string GetTimeStamp() { time_t ltime; time(<ime); -#ifdef _MSC_VER +#ifdef _WIN32 char ct[32]; ctime_s(ct, sizeof(ct), <ime); #else diff --git a/source/Memory.cpp b/source/Memory.cpp index a902f0e95..6896d1679 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -60,7 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // This is not available in Windows CRT: // https://en.cppreference.com/w/c/memory/aligned_alloc -#ifdef _MSC_VER +#ifdef _WIN32 // VirtualAlloc is aligned #define ALIGNED_ALLOC(size) (LPBYTE)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE) #define ALIGNED_FREE(ptr) VirtualFree(ptr, 0, MEM_RELEASE) @@ -244,7 +244,7 @@ static const UINT kNumAnnunciators = 4; static bool g_Annunciator[kNumAnnunciators] = {}; static const UINT num64KPages = 2; // number of 64K pages used to create hardware circular buffer -#ifdef _MSC_VER +#ifdef _WIN32 static HANDLE g_hMemImage = NULL; // NB. When not initialised, this handle is NULL (not INVALID_HANDLE_VALUE) #else static FILE * g_hMemTempFile = NULL; @@ -1528,7 +1528,7 @@ bool MemIsAddrCodeMemory(const USHORT addr) static void FreeMemImage(void) { -#ifdef _MSC_VER +#ifdef _WIN32 if (g_hMemImage) { for (UINT i = 0; i < num64KPages; i++) @@ -1559,7 +1559,7 @@ static void FreeMemImage(void) static LPBYTE AllocMemImage(void) { -#ifdef _MSC_VER +#ifdef _WIN32 LPBYTE baseAddr = NULL; // Allocate memory for 'memimage' (and the alias 'mem') diff --git a/source/SoundBufferBase.h b/source/SoundBufferBase.h new file mode 100644 index 000000000..5d6e4754c --- /dev/null +++ b/source/SoundBufferBase.h @@ -0,0 +1,26 @@ +#pragma once + +class SoundBufferBase +{ +public: + typedef SoundBufferBase* (*CreateSoundBufferFunc)(void); + static CreateSoundBufferFunc Create; + + virtual HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) = 0; + virtual HRESULT Release() = 0; + + virtual HRESULT SetCurrentPosition(DWORD dwNewPosition) = 0; + virtual HRESULT GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor) = 0; + + virtual HRESULT Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags) = 0; + virtual HRESULT Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2) = 0; + + virtual HRESULT Stop() = 0; + virtual HRESULT Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags) = 0; + + virtual HRESULT SetVolume(LONG lVolume) = 0; + virtual HRESULT GetVolume(LONG* lplVolume) = 0; + + virtual HRESULT GetStatus(LPDWORD lpdwStatus) = 0; + virtual HRESULT Restore() = 0; +}; \ No newline at end of file diff --git a/source/SoundCore.cpp b/source/SoundCore.cpp index 1f31def5b..01b66a0b2 100644 --- a/source/SoundCore.cpp +++ b/source/SoundCore.cpp @@ -72,6 +72,102 @@ VOICE::~VOICE(void) } } +#ifdef _MSC_VER + +class DSSoundBuffer : public SoundBufferBase +{ +private: + LPDIRECTSOUNDBUFFER pBuffer; + +public: + HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) override + { + if (!g_lpDS) + return E_FAIL; + + WAVEFORMATEX wavfmt; + DSBUFFERDESC dsbdesc; + + wavfmt.wFormatTag = WAVE_FORMAT_PCM; + wavfmt.nChannels = nChannels; + wavfmt.nSamplesPerSec = nSampleRate; + wavfmt.wBitsPerSample = 16; + wavfmt.nBlockAlign = wavfmt.nChannels == 1 ? 2 : 4; + wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec; + + memset(&dsbdesc, 0, sizeof(dsbdesc)); + dsbdesc.dwSize = sizeof(dsbdesc); + dsbdesc.dwBufferBytes = dwBufferSize; + dsbdesc.lpwfxFormat = &wavfmt; + dsbdesc.dwFlags = dwFlags | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; + + // Are buffers released when g_lpDS OR pVoice->lpDSBvoice is released? + // . From DirectX doc: + // "Buffer objects are owned by the device object that created them. When the + // device object is released, all buffers created by that object are also released..." + return g_lpDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL); + } + + HRESULT Release() override + { + if (!pBuffer) + return DS_OK; + + HRESULT hr = pBuffer->Release(); + pBuffer = NULL; + return hr; + } + + HRESULT SetCurrentPosition(DWORD dwNewPosition) override + { + return pBuffer->SetCurrentPosition(dwNewPosition); + } + + HRESULT GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor) + { + return pBuffer->GetCurrentPosition(lpdwCurrentPlayCursor, lpdwCurrentWriteCursor); + } + + HRESULT Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags) + { + return pBuffer->Lock(dwWriteCursor, dwWriteBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags); + } + + HRESULT Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2) + { + return pBuffer->Unlock(lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); + } + + HRESULT Stop() + { + return pBuffer->Stop(); + } + + HRESULT Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags) + { + return pBuffer->Play(dwReserved1, dwReserved2, dwFlags); + } + + HRESULT SetVolume(LONG lVolume) + { + return pBuffer->SetVolume(lVolume); + } + + HRESULT GetVolume(LONG* lplVolume) + { + return pBuffer->GetVolume(lplVolume); + } + + HRESULT GetStatus(LPDWORD lpdwStatus) + { + return pBuffer->GetStatus(lpdwStatus); + } + + HRESULT Restore() + { + return pBuffer->Restore(); + } +}; //----------------------------------------------------------------------------- @@ -137,9 +233,11 @@ static const char *DirectSound_ErrorText (HRESULT error) } #endif +#endif // _MSC_VER + //----------------------------------------------------------------------------- -HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, DWORD dwOffset, DWORD dwBytes, +HRESULT DSGetLock(SoundBufferBase* pVoice, DWORD dwOffset, DWORD dwBytes, SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0, SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1) { @@ -182,39 +280,20 @@ HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, DWORD dwOffset, DWORD dwBytes, //----------------------------------------------------------------------------- +SoundBufferBase::CreateSoundBufferFunc SoundBufferBase::Create = NULL; + HRESULT DSGetSoundBuffer(VOICE* pVoice, DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, const char* pszDevName) { - if (!g_lpDS) - return E_FAIL; - pVoice->name = pszDevName; - WAVEFORMATEX wavfmt; - DSBUFFERDESC dsbdesc; - - wavfmt.wFormatTag = WAVE_FORMAT_PCM; - wavfmt.nChannels = nChannels; - wavfmt.nSamplesPerSec = nSampleRate; - wavfmt.wBitsPerSample = 16; - wavfmt.nBlockAlign = wavfmt.nChannels==1 ? 2 : 4; - wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec; - - memset (&dsbdesc, 0, sizeof (dsbdesc)); - dsbdesc.dwSize = sizeof (dsbdesc); - dsbdesc.dwBufferBytes = dwBufferSize; - dsbdesc.lpwfxFormat = &wavfmt; - dsbdesc.dwFlags = dwFlags | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; - dsbdesc.szName = pszDevName; - - // Are buffers released when g_lpDS OR pVoice->lpDSBvoice is released? - // . From DirectX doc: - // "Buffer objects are owned by the device object that created them. When the - // device object is released, all buffers created by that object are also released..." - HRESULT hr = g_lpDS->CreateSoundBuffer(&dsbdesc, &pVoice->lpDSBvoice, NULL); - if(FAILED(hr)) + SoundBufferBase* soundBuffer = SoundBufferBase::Create(); + + HRESULT hr = soundBuffer->Init(dwFlags, dwBufferSize, nSampleRate, nChannels, pszDevName); + if (FAILED(hr)) return hr; // + pVoice->lpDSBvoice = soundBuffer; _ASSERT(g_uNumVoices < uMAX_VOICES); if(g_uNumVoices < uMAX_VOICES) @@ -256,7 +335,7 @@ bool DSVoiceStop(PVOICE Voice) HRESULT hr = Voice->lpDSBvoice->Stop(); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSStop failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSStop failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } @@ -281,7 +360,7 @@ bool DSZeroVoiceBuffer(PVOICE Voice, DWORD dwBufferSize) HRESULT hr = DSGetLock(Voice->lpDSBvoice, 0, 0, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, 0); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } @@ -291,14 +370,14 @@ bool DSZeroVoiceBuffer(PVOICE Voice, DWORD dwBufferSize) hr = Voice->lpDSBvoice->Unlock((void*)pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } hr = Voice->lpDSBvoice->Play(0,0,DSBPLAY_LOOPING); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSPlay failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSPlay failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } @@ -321,7 +400,7 @@ bool DSZeroVoiceWritableBuffer(PVOICE Voice, DWORD dwBufferSize) &pDSLockedBuffer1, &dwDSLockedBufferSize1); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } @@ -333,7 +412,7 @@ bool DSZeroVoiceWritableBuffer(PVOICE Voice, DWORD dwBufferSize) (void*)pDSLockedBuffer1, dwDSLockedBufferSize1); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), hr); + if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n", Voice->name.c_str(), (unsigned)hr); return false; } @@ -517,6 +596,13 @@ void SoundCore_TweakVolumes() //----------------------------------------------------------------------------- +#ifdef _MSC_VER + +static SoundBufferBase* CreateSoundBuffer(void) +{ + return new DSSoundBuffer(); +} + static UINT g_uDSInitRefCount = 0; bool DSInit() @@ -527,11 +613,13 @@ bool DSInit() return true; // Already initialised successfully } + SoundBufferBase::Create = CreateSoundBuffer; + num_sound_devices = 0; HRESULT hr = DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, NULL); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "DSEnumerate failed (%08X)\n",hr); + if(g_fh) fprintf(g_fh, "DSEnumerate failed (%08X)\n", (unsigned)hr); return false; } @@ -551,7 +639,7 @@ bool DSInit() break; } - if(g_fh) fprintf(g_fh, "DSCreate failed for sound device #%d (%08X)\n",x,hr); + if(g_fh) fprintf(g_fh, "DSCreate failed for sound device #%d (%08X)\n",x, (unsigned)hr); } if(!bCreatedOK) { @@ -564,7 +652,7 @@ bool DSInit() hr = g_lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL); if (FAILED(hr)) { - if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr); + if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n", (unsigned)hr); return false; } @@ -574,7 +662,7 @@ bool DSInit() hr = g_lpDS->GetCaps(&DSCaps); if(FAILED(hr)) { - if(g_fh) fprintf(g_fh, "GetCaps failed (%08X)\n",hr); + if(g_fh) fprintf(g_fh, "GetCaps failed (%08X)\n", (unsigned)hr); // Not fatal: so continue... } @@ -612,6 +700,8 @@ void DSUninit() SoundCore_StopTimer(); } +#endif + //----------------------------------------------------------------------------- LONG NewVolume(DWORD dwVolume, DWORD dwVolumeMax) diff --git a/source/SoundCore.h b/source/SoundCore.h index cdd2f46f6..feeffaf66 100644 --- a/source/SoundCore.h +++ b/source/SoundCore.h @@ -4,9 +4,11 @@ #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#include "SoundBufferBase.h" + struct VOICE { - LPDIRECTSOUNDBUFFER lpDSBvoice; + SoundBufferBase* lpDSBvoice; LPDIRECTSOUNDNOTIFY lpDSNotify; bool bActive; // Playback is active bool bMute; @@ -36,7 +38,7 @@ struct VOICE typedef VOICE* PVOICE; -HRESULT DSGetLock(LPDIRECTSOUNDBUFFER pVoice, DWORD dwOffset, DWORD dwBytes, +HRESULT DSGetLock(SoundBufferBase* pVoice, DWORD dwOffset, DWORD dwBytes, SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0, SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1); diff --git a/source/StdAfx.h b/source/StdAfx.h index f1c9cc014..edcffdde5 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -1,5 +1,8 @@ -#ifdef _MSC_VER +#ifdef _WIN32 +#ifdef __MINGW32__ +#define STRSAFE_NO_DEPRECATE +#endif #include #include @@ -33,6 +36,7 @@ typedef UINT64 uint64_t; #include #include #include +#include #include #include @@ -65,7 +69,7 @@ typedef UINT64 uint64_t; #define PTRDIFF_T_FMT "td" #endif -#else +#else // !_WIN32 #include #include @@ -78,11 +82,11 @@ typedef UINT64 uint64_t; #include #include -#include "windows.h" +#include "linux/libwindows/windows.h" //#define USE_SPEECH_API #define SIZE_T_FMT "zu" #define PTRDIFF_T_FMT "td" -#endif +#endif // _WIN32 diff --git a/source/StrFormat.h b/source/StrFormat.h index befb7d5b7..6a082aaa0 100644 --- a/source/StrFormat.h +++ b/source/StrFormat.h @@ -11,7 +11,7 @@ typedef UINT16 uint16_t; #include #endif -#ifdef _MSC_VER +#if _WIN32 #define ATTRIBUTE_FORMAT_PRINTF(a, b) #else #define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b))) diff --git a/source/Tfe/DNS.cpp b/source/Tfe/DNS.cpp index 2bd8d9271..97819678e 100644 --- a/source/Tfe/DNS.cpp +++ b/source/Tfe/DNS.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "DNS.h" -#ifndef _MSC_VER +#ifndef _WIN32 #include #include #include diff --git a/source/Tfe/IPRaw.cpp b/source/Tfe/IPRaw.cpp index ded35fab5..c96be54e2 100644 --- a/source/Tfe/IPRaw.cpp +++ b/source/Tfe/IPRaw.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "IPRaw.h" -#ifndef _MSC_VER +#ifndef _WIN32 #include #endif diff --git a/source/Tfe/PCapBackend.cpp b/source/Tfe/PCapBackend.cpp index be1261758..d96a8c8f2 100644 --- a/source/Tfe/PCapBackend.cpp +++ b/source/Tfe/PCapBackend.cpp @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../Common.h" #include "../Registry.h" -#ifdef _MSC_VER +#ifdef _WIN32 #include #endif @@ -76,7 +76,7 @@ void PCapBackend::update(const ULONG /* nExecutedCycles */) void PCapBackend::getMACAddress(const uint32_t address, MACAddress & mac) { // this is only expected to be called for IP addresses on the same network -#ifdef _MSC_VER +#ifdef _WIN32 const DWORD dwSourceAddress = INADDR_ANY; ULONG len = sizeof(MACAddress::address); SendARP(address, dwSourceAddress, mac.address, &len); diff --git a/source/Tfe/tfearch.cpp b/source/Tfe/tfearch.cpp index f0c42cbda..3da7489c2 100644 --- a/source/Tfe/tfearch.cpp +++ b/source/Tfe/tfearch.cpp @@ -27,7 +27,7 @@ /* #define WPCAP */ -#ifdef _MSC_VER +#ifdef _WIN32 #ifndef NOMINMAX #define NOMINMAX @@ -59,7 +59,7 @@ // once this is set, no further attempts to load npcap will be made static int tfe_cannot_use = 0; -#ifdef _MSC_VER +#ifdef _WIN32 typedef pcap_t *(*pcap_open_live_t)(const char *, int, int, int, char *); typedef void (*pcap_close_t)(pcap_t *); diff --git a/source/Uthernet2.cpp b/source/Uthernet2.cpp index 339bebb6e..e7ea5622b 100644 --- a/source/Uthernet2.cpp +++ b/source/Uthernet2.cpp @@ -43,9 +43,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // in the checks below we allow both in all cases // (errno == SOCK_EINPROGRESS || errno == SOCK_EWOULDBLOCK) // this works, bu we could instead define 2 functions and check only the correct one -#ifdef _MSC_VER +#ifdef _WIN32 +#ifndef _SSIZE_T_DEFINED typedef int ssize_t; +#endif typedef int socklen_t; #define sock_error() WSAGetLastError() @@ -197,7 +199,7 @@ void Socket::clearFD() { if (myFD != INVALID_SOCKET) { -#ifdef _MSC_VER +#ifdef _WIN32 closesocket(myFD); #else close(myFD); @@ -268,7 +270,7 @@ void Socket::process() { if (myFD != INVALID_SOCKET && mySocketStatus == W5100_SN_SR_SOCK_SYNSENT) { -#ifdef _MSC_VER +#ifdef _WIN32 FD_SET writefds, exceptfds; FD_ZERO(&writefds); FD_ZERO(&exceptfds); @@ -368,7 +370,7 @@ const std::string& Uthernet2::GetSnapshotCardName() Uthernet2::Uthernet2(UINT slot) : NetworkCard(CT_Uthernet2, slot) { -#ifdef _MSC_VER +#ifdef _WIN32 WSADATA wsaData; myWSAStartup = WSAStartup(MAKEWORD(2, 2), &wsaData); if (myWSAStartup) @@ -384,7 +386,7 @@ Uthernet2::Uthernet2(UINT slot) : NetworkCard(CT_Uthernet2, slot) Uthernet2::~Uthernet2() { -#ifdef _MSC_VER +#ifdef _WIN32 if (myWSAStartup == 0) { WSACleanup(); @@ -917,7 +919,7 @@ void Uthernet2::openSystemSocket(const size_t i, const int type, const int proto } else { -#ifdef _MSC_VER +#ifdef _WIN32 u_long on = 1; const int res = ioctlsocket(fd, FIONBIO, &on); #else diff --git a/source/Uthernet2.h b/source/Uthernet2.h index 892f7379e..9e22f63d3 100644 --- a/source/Uthernet2.h +++ b/source/Uthernet2.h @@ -10,7 +10,7 @@ struct MACAddress; struct Socket { -#ifdef _MSC_VER +#ifdef _WIN32 typedef SOCKET socket_t; #else typedef int socket_t; @@ -87,7 +87,7 @@ class Uthernet2 : public NetworkCard private: bool myVirtualDNSEnabled; // extended virtualisation of DNS (not present in the real U II card) -#ifdef _MSC_VER +#ifdef _WIN32 int myWSAStartup; #endif diff --git a/source/Video.cpp b/source/Video.cpp index a8a352381..c409ab453 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -518,7 +518,7 @@ void Video::Video_MakeScreenShot(FILE *pFile, const VideoScreenShot_e ScreenShot ); #define EXPECTED_BMP_HEADER_SIZE (14 + 40) -#ifdef _MSC_VER +#ifdef _WIN32 char sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[ sizeof( WinBmpHeader_t ) == EXPECTED_BMP_HEADER_SIZE]; /**/ sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[0]=0; #else diff --git a/source/frontends/common2/CMakeLists.txt b/source/frontends/common2/CMakeLists.txt index 10af3f568..4928877ee 100644 --- a/source/frontends/common2/CMakeLists.txt +++ b/source/frontends/common2/CMakeLists.txt @@ -4,10 +4,6 @@ set(SOURCE_FILES commonframe.cpp commoncontext.cpp controllerdoublepress.cpp - gnuframe.cpp - fileregistry.cpp - ptreeregistry.cpp - programoptions.cpp utils.cpp timer.cpp speed.cpp @@ -17,15 +13,26 @@ set(HEADER_FILES commonframe.h commoncontext.h controllerdoublepress.h - gnuframe.h - fileregistry.h - ptreeregistry.h - programoptions.h utils.h timer.h speed.h ) +if (BUILD_APPLEN OR BUILD_QAPPLE OR BUILD_SA2) + set(SOURCE_FILES ${SOURCE_FILES} + fileregistry.cpp + gnuframe.cpp + programoptions.cpp + ptreeregistry.cpp + ) + set(HEADER_FILES ${HEADER_FILES} + fileregistry.h + gnuframe.h + programoptions.h + ptreeregistry.h + ) +endif() + add_library(common2 STATIC ${SOURCE_FILES} ${HEADER_FILES} @@ -33,21 +40,36 @@ add_library(common2 STATIC target_compile_features(common2 PUBLIC cxx_std_17) -find_package(Boost REQUIRED - COMPONENTS program_options - ) - target_include_directories(common2 PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${Boost_INCLUDE_DIRS} ) target_link_libraries(common2 PRIVATE - Boost::program_options appleii - windows ) +if (BUILD_APPLEN OR BUILD_QAPPLE OR BUILD_SA2) + # boost is needed by programoptions and ptreeregistry, which aren't used + # by libretro. need better separation of libretro common and linux common + find_package(Boost REQUIRED + COMPONENTS program_options + ) + + target_include_directories(common2 PRIVATE + ${Boost_INCLUDE_DIRS} + ) + + target_link_libraries(common2 PRIVATE + Boost::program_options + ) +endif() + +if (NOT WIN32) + target_link_libraries(common2 PRIVATE + windows + ) +endif() + file(RELATIVE_PATH ROOT_PATH ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}) if ("${ROOT_PATH}" STREQUAL "") # if the 2 paths are the same diff --git a/source/frontends/common2/commonframe.cpp b/source/frontends/common2/commonframe.cpp index ad30ead14..177634a03 100644 --- a/source/frontends/common2/commonframe.cpp +++ b/source/frontends/common2/commonframe.cpp @@ -1,11 +1,7 @@ #include "StdAfx.h" #include "frontends/common2/commonframe.h" #include "frontends/common2/programoptions.h" -#include "linux/resources.h" -#include -#include -#include #include #include "CardManager.h" @@ -20,11 +16,11 @@ namespace common2 { - CommonFrame::CommonFrame(const EmulatorOptions & options) - : LinuxFrame(options.autoBoot) - , mySpeed(options.fixedSpeed) - , mySynchroniseWithTimer(options.syncWithTimer) - , myAllowVideoUpdate(!options.noVideoUpdate) + CommonFrame::CommonFrame(bool autoBoot, bool fixedSpeed, bool syncWithTimer, bool allowVideoUpdate) + : LinuxFrame(autoBoot) + , mySpeed(fixedSpeed) + , mySynchroniseWithTimer(syncWithTimer) + , myAllowVideoUpdate(allowVideoUpdate) { myLastSync = std::chrono::steady_clock::now(); } @@ -36,48 +32,6 @@ namespace common2 ResetHardware(); } - BYTE* CommonFrame::GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) - { - myResource.clear(); - - const std::string & filename = getResourceName(id); - const std::string path = getResourcePath(filename); - - const int fd = open(path.c_str(), O_RDONLY); - - if (fd != -1) - { - struct stat stdbuf; - if ((fstat(fd, &stdbuf) == 0) && S_ISREG(stdbuf.st_mode)) - { - const off_t size = stdbuf.st_size; - std::vector data(size); - const ssize_t rd = read(fd, data.data(), size); - if (rd == expectedSize) - { - std::swap(myResource, data); - } - } - close(fd); - } - - if (myResource.empty()) - { - LogFileOutput("FindResource: could not load resource %s\n", filename.c_str()); - } - - return myResource.data(); - } - - std::string CommonFrame::getBitmapFilename(const std::string & resource) - { - if (resource == "CHARSET82") return "CHARSET82.bmp"; - if (resource == "CHARSET8M") return "CHARSET8M.bmp"; - if (resource == "CHARSET8C") return "CHARSET8C.bmp"; - - return resource; - } - void CommonFrame::ResetSpeed() { mySpeed.reset(); diff --git a/source/frontends/common2/commonframe.h b/source/frontends/common2/commonframe.h index 6b0d62a52..6c6315826 100644 --- a/source/frontends/common2/commonframe.h +++ b/source/frontends/common2/commonframe.h @@ -11,17 +11,14 @@ namespace common2 { - struct EmulatorOptions; class CommonFrame : public LinuxFrame { public: - CommonFrame(const EmulatorOptions & options); + CommonFrame(bool autoBoot, bool fixedSpeed, bool syncWithTimer, bool allowVideoUpdate); void Begin() override; - BYTE* GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) override; - virtual void ResetSpeed(); void ExecuteOneFrame(const int64_t microseconds); @@ -40,10 +37,6 @@ namespace common2 void LoadSnapshot() override; protected: - virtual std::string getResourcePath(const std::string & filename) = 0; - - static std::string getBitmapFilename(const std::string & resource); - virtual void SetFullSpeed(const bool value); virtual bool CanDoFullSpeed(); @@ -57,8 +50,6 @@ namespace common2 bool mySynchroniseWithTimer; std::chrono::time_point myLastSync; - std::vector myResource; - private: const bool myAllowVideoUpdate; CConfigNeedingRestart myHardwareConfig; diff --git a/source/frontends/common2/fileregistry.cpp b/source/frontends/common2/fileregistry.cpp index cc3c365d3..d8851e876 100644 --- a/source/frontends/common2/fileregistry.cpp +++ b/source/frontends/common2/fileregistry.cpp @@ -85,6 +85,15 @@ namespace common2 std::string GetHomeDir() { +#ifdef _WIN32 + char self[1024]; + if (GetModuleFileNameA(0, self, sizeof(self)) >= sizeof(self)) + { + throw std::runtime_error("${HOME} not set, cannot locate configuration file"); + } + + return std::string(self); +#else const char* homeDir = getenv("HOME"); if (!homeDir) { @@ -92,10 +101,14 @@ namespace common2 } return std::string(homeDir); +#endif } std::string GetConfigFile(const std::string & filename) { +#ifdef _WIN32 + return GetHomeDir() + "/" + filename; +#else const std::string dir = GetHomeDir() + "/.applewin"; const int status = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if (!status || (errno == EEXIST)) @@ -108,6 +121,7 @@ namespace common2 LogFileOutput("No registry. Cannot create %s in %s: %s\n", filename.c_str(), dir.c_str(), s); return std::string(); } +#endif } std::shared_ptr CreateFileRegistry(const EmulatorOptions & options) @@ -119,7 +133,11 @@ namespace common2 if (options.useQtIni) { +#ifdef _WIN32 + filename = homeDir + "\\" + APPLICATION_NAME + ".conf"; +#else filename = homeDir + "/.config/" + ORGANIZATION_NAME + "/" + APPLICATION_NAME + ".conf"; +#endif saveOnExit = false; } else diff --git a/source/frontends/common2/gnuframe.cpp b/source/frontends/common2/gnuframe.cpp index 85623e26f..85e290873 100644 --- a/source/frontends/common2/gnuframe.cpp +++ b/source/frontends/common2/gnuframe.cpp @@ -1,8 +1,13 @@ #include "StdAfx.h" + #include "frontends/common2/gnuframe.h" #include "frontends/common2/fileregistry.h" +#include "frontends/common2/programoptions.h" + +#include "linux/resources.h" #include +#include #include #include @@ -13,6 +18,10 @@ #include "Core.h" #include "config.h" +#ifdef __MINGW32__ +#define realpath(N,R) _fullpath((R),(N),_MAX_PATH) +#endif + namespace { @@ -36,7 +45,11 @@ namespace char self[1024] = {0}; -#ifdef __APPLE__ +#ifdef _WIN32 + int ch = GetModuleFileNameA(0, self, sizeof(self)); + if (ch >= sizeof(self)) + ch = -1; +#elif defined(__APPLE__) uint32_t size = sizeof(self); const int ch = _NSGetExecutablePath(self, &size); #else @@ -77,9 +90,8 @@ namespace namespace common2 { - GNUFrame::GNUFrame(const EmulatorOptions & options) - : CommonFrame(options) + : CommonFrame(options.autoBoot, options.fixedSpeed, options.syncWithTimer, !options.noVideoUpdate) , myHomeDir(GetHomeDir()) , myResourceFolder(getResourceFolder("/resource/")) { @@ -87,6 +99,40 @@ namespace common2 g_sProgramDir = getResourceFolder("/bin/"); } + + BYTE* GNUFrame::GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) + { + myResource.clear(); + + const std::string & filename = getResourceName(id); + const std::string path = getResourcePath(filename); + + const int fd = open(path.c_str(), O_RDONLY); + + if (fd != -1) + { + struct stat stdbuf; + if ((fstat(fd, &stdbuf) == 0) && S_ISREG(stdbuf.st_mode)) + { + const off_t size = stdbuf.st_size; + std::vector data(size); + const ssize_t rd = read(fd, data.data(), size); + if (rd == expectedSize) + { + std::swap(myResource, data); + } + } + close(fd); + } + + if (myResource.empty()) + { + LogFileOutput("FindResource: could not load resource %s\n", filename.c_str()); + } + + return myResource.data(); + } + std::string GNUFrame::getResourcePath(const std::string & filename) { return myResourceFolder + filename; diff --git a/source/frontends/common2/gnuframe.h b/source/frontends/common2/gnuframe.h index 4eed57df6..4e01ef672 100644 --- a/source/frontends/common2/gnuframe.h +++ b/source/frontends/common2/gnuframe.h @@ -5,6 +5,7 @@ namespace common2 { + struct EmulatorOptions; class GNUFrame : public CommonFrame { @@ -12,11 +13,16 @@ namespace common2 GNUFrame(const common2::EmulatorOptions & option); std::string Video_GetScreenShotFolder() const override; - std::string getResourcePath(const std::string & filename) override; + BYTE* GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) override; + + protected: + virtual std::string getResourcePath(const std::string& filename); private: const std::string myHomeDir; const std::string myResourceFolder; + + std::vector myResource; }; } diff --git a/source/frontends/common2/ptreeregistry.cpp b/source/frontends/common2/ptreeregistry.cpp index f6f47de60..af52e735a 100644 --- a/source/frontends/common2/ptreeregistry.cpp +++ b/source/frontends/common2/ptreeregistry.cpp @@ -1,3 +1,5 @@ +#include "StdAfx.h" + #include "frontends/common2/ptreeregistry.h" #include diff --git a/source/frontends/libretro/CMakeLists.txt b/source/frontends/libretro/CMakeLists.txt index b1711578f..c0ebca3a5 100644 --- a/source/frontends/libretro/CMakeLists.txt +++ b/source/frontends/libretro/CMakeLists.txt @@ -11,10 +11,55 @@ set(SOURCE_FILES rdirectsound.cpp retroregistry.cpp retroframe.cpp + retroframeresources.cpp diskcontrol.cpp serialisation.cpp ) +macro(add_resource output source) + set(add_resource_command "./resource2inl.sh ../../../resource/${source} ${output}") + add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${output}.inl" + COMMAND bash -c "${add_resource_command}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS "../../../resource/${source}" + ) + set(RESOURCE_FILES ${RESOURCE_FILES} "${output}.inl") +endmacro(add_resource) + +add_resource(rom_Apple2 Apple2.rom) +add_resource(rom_Apple2_Plus Apple2_Plus.rom) +add_resource(rom_Apple2_Video Apple2_Video.rom) +add_resource(rom_Apple2_JPlus Apple2_JPlus.rom) +add_resource(rom_Apple2_JPlus_Video Apple2_JPlus_Video.rom) +add_resource(rom_Apple2e Apple2e.rom) +add_resource(rom_Apple2e_Enhanced Apple2e_Enhanced.rom) +add_resource(rom_Apple2e_Enhanced_Video Apple2e_Enhanced_Video.rom) +add_resource(rom_Base64A Base64A.rom) +add_resource(rom_Base64A_German_Video Base64A_German_Video.rom) +add_resource(rom_DISK2 DISK2.rom) +add_resource(rom_DISK2_13sector DISK2-13sector.rom) +add_resource(rom_Mockingboard_D Mockingboard-D.rom) +add_resource(rom_MouseInterface MouseInterface.rom) +add_resource(rom_Parallel Parallel.rom) +add_resource(rom_PRAVETS82 PRAVETS82.ROM) +add_resource(rom_PRAVETS8C PRAVETS8C.ROM) +add_resource(rom_PRAVETS8M PRAVETS8M.ROM) +add_resource(rom_SSC SSC.rom) +add_resource(rom_ThunderClockPlus ThunderClockPlus.rom) +add_resource(rom_TK3000e TK3000e.rom) +add_resource(rom_TKClock TKClock.rom) + +add_resource(bin_Hddrvr Hddrvr.bin) +add_resource(bin_Hddrvr_v2 Hddrvr-v2.bin) +add_resource(bin_HDC_SmartPort HDC-SmartPort.bin) + +add_resource(bmp_CHARSET82 CHARSET82.bmp) +add_resource(bmp_CHARSET8C CHARSET8C.bmp) +add_resource(bmp_CHARSET8M CHARSET8M.bmp) + +add_custom_target(resource_files DEPENDS ${RESOURCE_FILES}) + set(HEADER_FILES libretro-common/include/libretro.h environment.h @@ -36,6 +81,7 @@ add_library(applewin_libretro SHARED ${SOURCE_FILES} ${HEADER_FILES} ) +add_dependencies(applewin_libretro resource_files) target_compile_features(applewin_libretro PUBLIC cxx_std_17) @@ -51,7 +97,6 @@ target_link_libraries(applewin_libretro PRIVATE $<${static_stdcpp_fs}:stdc++fs> appleii common2 - windows ) # just call it "applewin_libretro.so" as per libretro standard diff --git a/source/frontends/libretro/diskcontrol.cpp b/source/frontends/libretro/diskcontrol.cpp index 67fcb4d26..fda656970 100644 --- a/source/frontends/libretro/diskcontrol.cpp +++ b/source/frontends/libretro/diskcontrol.cpp @@ -34,7 +34,7 @@ namespace if (pos == std::string::npos) { path = line; - label = path.stem(); + label = path.stem().u8string(); } else { @@ -80,7 +80,7 @@ namespace ra2 // a bit of a workaround to a save state issue, where the disk folder is lost // this will only support 1 disk const std::filesystem::path filePath(path); - myCurrentDiskFolder = filePath.parent_path().string(); + myCurrentDiskFolder = filePath.parent_path().u8string(); } bool DiskControl::insertDisk(const std::string & path) @@ -94,7 +94,8 @@ namespace ra2 myImages.clear(); const std::filesystem::path filePath(path); - myImages.push_back({filePath.native(), filePath.stem(), writeProtected, createIfNecessary}); + DiskInfo diskInfo; + myImages.push_back({ filePath.u8string(), filePath.stem().u8string(), writeProtected, createIfNecessary }); myEjected = false; return true; } @@ -114,7 +115,7 @@ namespace ra2 myImages.clear(); const std::filesystem::path parent = playlistPath.parent_path(); const std::filesystem::path savePath(ra2::save_directory); - const std::string playlistStem = playlistPath.stem(); + const std::string playlistStem = playlistPath.stem().u8string(); std::string line; while (std::getline(playlist, line)) @@ -139,7 +140,7 @@ namespace ra2 const std::filesystem::path imagePath = savePath / filename; // TODO: this disk is NOT formatted - myImages.push_back({imagePath.native(), label, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_CREATE}); + myImages.push_back({imagePath.u8string(), label, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_CREATE}); } else if (!startsWith(line, M3U_COMMENT)) { @@ -151,7 +152,7 @@ namespace ra2 { imagePath = parent / imagePath; } - myImages.push_back({imagePath.native(), label, IMAGE_FORCE_WRITE_PROTECTED, IMAGE_DONT_CREATE}); + myImages.push_back({imagePath.u8string(), label, IMAGE_FORCE_WRITE_PROTECTED, IMAGE_DONT_CREATE}); } } @@ -285,8 +286,8 @@ namespace ra2 { const std::filesystem::path filePath(path); - myImages[index].path = filePath.native(); - myImages[index].label = filePath.stem(); + myImages[index].path = filePath.u8string(); + myImages[index].label = filePath.stem().u8string(); myImages[index].writeProtected = IMAGE_FORCE_WRITE_PROTECTED; myImages[index].createIfNecessary = IMAGE_DONT_CREATE; return true; diff --git a/source/frontends/libretro/game.cpp b/source/frontends/libretro/game.cpp index 90350054f..8189f7c28 100644 --- a/source/frontends/libretro/game.cpp +++ b/source/frontends/libretro/game.cpp @@ -4,8 +4,6 @@ #include "frontends/libretro/retroframe.h" #include "frontends/libretro/rkeyboard.h" #include "frontends/common2/utils.h" -#include "frontends/common2/ptreeregistry.h" -#include "frontends/common2/programoptions.h" #include "Common.h" #include "Interface.h" @@ -13,29 +11,10 @@ #include "linux/keyboardbuffer.h" #include "linux/paddle.h" #include "linux/context.h" +#include "linux/registryclass.h" #include "libretro.h" -#define APPLEWIN_RETRO_CONF "/tmp/applewin.retro.conf" - -namespace -{ - - void saveRegistryToINI(const std::shared_ptr & registry) - { - try - { - registry->saveToINIFile(APPLEWIN_RETRO_CONF); - ra2::display_message("Configuration saved to: " APPLEWIN_RETRO_CONF); - } - catch (const std::exception & e) - { - ra2::display_message(std::string("Error saving configuration: ") + e.what()); - } - } - -} - namespace ra2 { @@ -47,13 +26,11 @@ namespace ra2 , myAudioSource(AudioSource::UNKNOWN) , myKeyboardType(KeyboardType::ASCII) { - myLoggerContext = std::make_shared(true); + myLoggerContext = std::make_shared(false); myRegistry = CreateRetroRegistry(); myRegistryContext = std::make_shared(myRegistry); - common2::EmulatorOptions defaultOptions; - defaultOptions.fixedSpeed = true; - myFrame = std::make_shared(defaultOptions); + myFrame = std::make_shared(); refreshVariables(); @@ -290,10 +267,6 @@ namespace ra2 { myFrame->Cycle50ScanLines(); } - if (checkButton(RETRO_DEVICE_ID_JOYPAD_L2)) - { - saveRegistryToINI(myRegistry); - } if (checkButton(RETRO_DEVICE_ID_JOYPAD_R2)) { switch (myAudioSource) diff --git a/source/frontends/libretro/game.h b/source/frontends/libretro/game.h index e0703407f..302033154 100644 --- a/source/frontends/libretro/game.h +++ b/source/frontends/libretro/game.h @@ -13,11 +13,7 @@ class LoggerContext; class RegistryContext; - -namespace common2 -{ - class PTreeRegistry; -} +class Registry; namespace ra2 { @@ -59,7 +55,7 @@ namespace ra2 // keep them in this order! std::shared_ptr myLoggerContext; - std::shared_ptr myRegistry; + std::shared_ptr myRegistry; std::shared_ptr myRegistryContext; std::shared_ptr myFrame; diff --git a/source/frontends/libretro/libretro.cpp b/source/frontends/libretro/libretro.cpp index 61f62e1f6..1901f6d37 100644 --- a/source/frontends/libretro/libretro.cpp +++ b/source/frontends/libretro/libretro.cpp @@ -311,7 +311,7 @@ void retro_run(void) bool retro_load_game(const retro_game_info *info) { ourGame.reset(); - ra2::log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + ra2::log_cb(RETRO_LOG_INFO, "RA2: %s %s\n", __FUNCTION__, info->path); enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; if (!ra2::environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) diff --git a/source/frontends/libretro/rdirectsound.cpp b/source/frontends/libretro/rdirectsound.cpp index 8e65fa8e1..d81a971f8 100644 --- a/source/frontends/libretro/rdirectsound.cpp +++ b/source/frontends/libretro/rdirectsound.cpp @@ -1,8 +1,9 @@ -#include "StdAfx.h" +#include + #include "frontends/libretro/rdirectsound.h" #include "frontends/libretro/environment.h" -#include "linux/linuxinterface.h" +#include "linux/soundbuffer.h" #include #include @@ -37,41 +38,49 @@ namespace return ra2::AudioSource::UNKNOWN; } - class DirectSoundGenerator : public IDirectSoundBuffer + class SoundGenerator : public SoundBuffer { public: - DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc); - - virtual HRESULT Release() override; + HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) override; + HRESULT Release() override; void writeAudio(const size_t fps, const bool write); bool isRunning(); ra2::AudioSource getSource() const; + void setSource(ra2::AudioSource audioSource) { myAudioSource = audioSource; } private: - const ra2::AudioSource myAudioSource; + ra2::AudioSource myAudioSource = ra2::AudioSource::UNKNOWN; std::vector myMixerBuffer; void mixBuffer(const void * ptr, const size_t size); }; - std::unordered_map > activeSoundGenerators; + std::vector activeSoundGenerators; - DirectSoundGenerator::DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc) - : IDirectSoundBuffer(lpcDSBufferDesc) - , myAudioSource(getAudioSourceFromName(myName)) + HRESULT SoundGenerator::Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) { + myAudioSource = getAudioSourceFromName(pDevName); + return SoundBuffer::Init(dwFlags, dwBufferSize, nSampleRate, nChannels, pDevName); } - HRESULT DirectSoundGenerator::Release() + HRESULT SoundGenerator::Release() { - activeSoundGenerators.erase(this); - return IUnknown::Release(); + for (auto iter = activeSoundGenerators.begin(); iter != activeSoundGenerators.end(); ++iter) + { + if (*iter == this) + { + activeSoundGenerators.erase(iter); + break; + } + } + + return SoundBuffer::Release(); } - bool DirectSoundGenerator::isRunning() + bool SoundGenerator::isRunning() { DWORD dwStatus; GetStatus(&dwStatus); @@ -85,12 +94,12 @@ namespace } } - ra2::AudioSource DirectSoundGenerator::getSource() const + ra2::AudioSource SoundGenerator::getSource() const { return myAudioSource; } - void DirectSoundGenerator::mixBuffer(const void * ptr, const size_t size) + void SoundGenerator::mixBuffer(const void * ptr, const size_t size) { const int16_t frames = size / (sizeof(int16_t) * myChannels); const int16_t * data = static_cast(ptr); @@ -122,7 +131,7 @@ namespace ra2::audio_batch_cb(myMixerBuffer.data(), frames); } - void DirectSoundGenerator::writeAudio(const size_t fps, const bool write) + void SoundGenerator::writeAudio(const size_t fps, const bool write) { const size_t frames = mySampleRate / fps; const size_t bytesToRead = frames * myChannels * sizeof(int16_t); @@ -147,12 +156,24 @@ namespace } -IDirectSoundBuffer * iCreateDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc) +static SoundBufferBase* CreateSoundBuffer(void) +{ + SoundGenerator * generator = new SoundGenerator(); + activeSoundGenerators.push_back(generator); + return generator; +} + +extern bool g_bDSAvailable; + +bool DSInit() +{ + SoundBufferBase::Create = CreateSoundBuffer; + g_bDSAvailable = true; + return true; +} + +void DSUninit() { - std::shared_ptr generator = std::make_shared(lpcDSBufferDesc); - DirectSoundGenerator * ptr = generator.get(); - activeSoundGenerators[ptr] = generator; - return ptr; } namespace ra2 @@ -161,9 +182,8 @@ namespace ra2 void writeAudio(const AudioSource selectedSource, const size_t fps) { bool found = false; - for (const auto & it : activeSoundGenerators) + for (auto* generator : activeSoundGenerators) { - const auto & generator = it.second; if (generator->isRunning()) { const bool selected = !found && (selectedSource == generator->getSource()); diff --git a/source/frontends/libretro/resource2inl.sh b/source/frontends/libretro/resource2inl.sh new file mode 100755 index 000000000..b2d584060 --- /dev/null +++ b/source/frontends/libretro/resource2inl.sh @@ -0,0 +1,15 @@ +INPUT_FILE=$1 +OUTPUT_FILE=$2.inl + +echo "#pragma once" > "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" +echo "static BYTE _$2[] = {" >> "$OUTPUT_FILE" + +# dump the entire file as hex codes using a ":" as a placeholder for a newline +# then pipe that through sed to remove the last comma and any empty trailing records +# and finally, convert the placeholders back into real newlines +# have to use a placeholder so the next command doesn't process every individual file +hexdump -v -e '16/1 "0x%02X," ":"' "$INPUT_FILE" | sed 's/,[0x ,]*:$//' | sed 's/:/\n/g' >> "$OUTPUT_FILE" +# ^------------------- dump -------------------^ ^- remove trailing -^ ^- newlines -^ + +echo "};" >> "$OUTPUT_FILE" diff --git a/source/frontends/libretro/retroframe.cpp b/source/frontends/libretro/retroframe.cpp index a822b76fc..aff174d12 100644 --- a/source/frontends/libretro/retroframe.cpp +++ b/source/frontends/libretro/retroframe.cpp @@ -78,18 +78,13 @@ namespace namespace ra2 { - RetroFrame::RetroFrame(const common2::EmulatorOptions & options) - : common2::GNUFrame(options) + RetroFrame::RetroFrame() + : common2::CommonFrame(true, true, false, true) { } void RetroFrame::FrameRefreshStatus(int drawflags) { - if (drawflags & DRAW_TITLE) - { - GetAppleWindowTitle(); - display_message(g_pAppTitle.c_str()); - } } void RetroFrame::VideoPresentScreen() @@ -138,43 +133,9 @@ namespace ra2 myVideoBuffer.clear(); } - void RetroFrame::GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) - { - const std::string filename = getBitmapFilename(lpBitmapName); - const std::string path = getResourcePath(filename); - - std::vector buffer; - readFileToBuffer(path, buffer); - - if (!buffer.empty()) - { - int32_t width, height; - uint16_t bpp; - const char * data; - uint32_t size; - const bool res = getBitmapData(buffer, width, height, bpp, data, size); - - if (res && height > 0 && size <= cb) - { - const size_t length = size / height; - // rows are stored upside down - char * out = static_cast(lpvBits); - for (size_t row = 0; row < height; ++row) - { - const char * src = data + row * length; - char * dst = out + (height - row - 1) * length; - memcpy(dst, src, length); - } - return; - } - } - - log_cb(RETRO_LOG_INFO, "RA2: %s. Missing bitmap '%s'\n", __FUNCTION__, lpBitmapName); - CommonFrame::GetBitmap(lpBitmapName, cb, lpvBits); - } - int RetroFrame::FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) { + display_message(lpText, 60); log_cb(RETRO_LOG_INFO, "RA2: %s: %s - %s\n", __FUNCTION__, lpCaption, lpText); return IDOK; } @@ -193,7 +154,7 @@ namespace ra2 void RetroFrame::Begin() { const common2::RestoreCurrentDirectory restoreChDir; - common2::GNUFrame::Begin(); + common2::CommonFrame::Begin(); } diff --git a/source/frontends/libretro/retroframe.h b/source/frontends/libretro/retroframe.h index 1ae81bfc6..b7d6eab37 100644 --- a/source/frontends/libretro/retroframe.h +++ b/source/frontends/libretro/retroframe.h @@ -1,16 +1,16 @@ #pragma once -#include "frontends/common2/gnuframe.h" +#include "frontends/common2/commonframe.h" #include namespace ra2 { - class RetroFrame : public common2::GNUFrame + class RetroFrame : public common2::CommonFrame { public: - RetroFrame(const common2::EmulatorOptions & options); + RetroFrame(); void VideoPresentScreen() override; void FrameRefreshStatus(int drawflags) override; @@ -20,6 +20,9 @@ namespace ra2 int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) override; void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) override; + std::string Video_GetScreenShotFolder() const override { return std::string(""); } + BYTE* GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) override; + protected: virtual void SetFullSpeed(const bool value) override; virtual bool CanDoFullSpeed() override; diff --git a/source/frontends/libretro/retroframeresources.cpp b/source/frontends/libretro/retroframeresources.cpp new file mode 100644 index 000000000..6dfd7b0d7 --- /dev/null +++ b/source/frontends/libretro/retroframeresources.cpp @@ -0,0 +1,116 @@ +#include "StdAfx.h" +#include "frontends/libretro/retroframe.h" +#include "frontends/libretro/environment.h" + +#include "linux/resources.h" + +#include "../resource/resource.h" +#include "rom_Apple2.inl" +#include "rom_Apple2_Plus.inl" +#include "rom_Apple2_Video.inl" +#include "rom_Apple2_JPlus.inl" +#include "rom_Apple2_JPlus_Video.inl" +#include "rom_Apple2e.inl" +#include "rom_Apple2e_Enhanced.inl" +#include "rom_Apple2e_Enhanced_Video.inl" +#include "rom_Base64A.inl" +#include "rom_Base64A_German_Video.inl" +#include "rom_DISK2.inl" +#include "rom_DISK2_13sector.inl" +#include "rom_Mockingboard_D.inl" +#include "rom_MouseInterface.inl" +#include "rom_Parallel.inl" +#include "rom_PRAVETS82.inl" +#include "rom_PRAVETS8C.inl" +#include "rom_PRAVETS8M.inl" +#include "rom_SSC.inl" +#include "rom_ThunderClockPlus.inl" +#include "rom_TK3000e.inl" +#include "rom_TKClock.inl" + +#include "bin_Hddrvr.inl" +#include "bin_Hddrvr_v2.inl" +#include "bin_HDC_SmartPort.inl" + +#include "bmp_CHARSET82.inl" +#include "bmp_CHARSET8C.inl" +#include "bmp_CHARSET8M.inl" + +namespace ra2 +{ + + void RetroFrame::GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) + { + if (strcmp(lpBitmapName, "CHARSET8C") == 0) + memcpy(lpvBits, _bmp_CHARSET8C, cb); + else if (strcmp(lpBitmapName, "CHARSET8M") == 0) + memcpy(lpvBits, _bmp_CHARSET8M, cb); + else if (strcmp(lpBitmapName, "CHARSET82") == 0) + memcpy(lpvBits, _bmp_CHARSET82, cb); + else + { + log_cb(RETRO_LOG_INFO, "RA2: %s. Missing bitmap '%s'\n", __FUNCTION__, lpBitmapName); + memset(lpvBits, 0, cb); + } + } + + BYTE* RetroFrame::GetResource(WORD id, LPCSTR lpType, DWORD expectedSize) + { + switch (id) + { + case IDR_APPLE2_ROM: + return _rom_Apple2; + case IDR_APPLE2_PLUS_ROM: + return _rom_Apple2_Plus; + case IDR_APPLE2_VIDEO_ROM: + return _rom_Apple2_Video; + case IDR_APPLE2_JPLUS_ROM: + return _rom_Apple2_JPlus; + case IDR_APPLE2_JPLUS_VIDEO_ROM: + return _rom_Apple2_JPlus_Video; + case IDR_APPLE2E_ROM: + return _rom_Apple2e; + case IDR_APPLE2E_ENHANCED_ROM: + return _rom_Apple2e_Enhanced; + case IDR_APPLE2E_ENHANCED_VIDEO_ROM: + return _rom_Apple2e_Enhanced_Video; + case IDR_BASE_64A_ROM: + return _rom_Base64A; + case IDR_BASE64A_VIDEO_ROM: + return _rom_Base64A_German_Video; + case IDR_DISK2_16SECTOR_FW: + return _rom_DISK2; + case IDR_DISK2_13SECTOR_FW: + return _rom_DISK2_13sector; + case IDR_HDC_SMARTPORT_FW: + return _bin_HDC_SmartPort; + case IDR_HDDRVR_FW: + return _bin_Hddrvr; + case IDR_HDDRVR_V2_FW: + return _bin_Hddrvr_v2; + case IDR_MOCKINGBOARD_D_FW: + return _rom_Mockingboard_D; + case IDR_MOUSEINTERFACE_FW: + return _rom_MouseInterface; + case IDR_PRAVETS_82_ROM: + return _rom_PRAVETS82; + case IDR_PRAVETS_8M_ROM: + return _rom_PRAVETS8M; + case IDR_PRAVETS_8C_ROM: + return _rom_PRAVETS8C; + case IDR_PRINTDRVR_FW: + return _rom_Parallel; + case IDR_SSC_FW: + return _rom_SSC; + case IDR_TK3000_2E_ROM: + return _rom_TK3000e; + case IDR_TKCLOCK_FW: + return _rom_TKClock; + case IDR_THUNDERCLOCKPLUS_FW: + return _rom_ThunderClockPlus; + default: + log_cb(RETRO_LOG_INFO, "RA2: %s. Missing resource %u: '%s'\n", __FUNCTION__, id, getResourceName(id).c_str()); + return NULL; + } + } +} diff --git a/source/frontends/libretro/retroregistry.cpp b/source/frontends/libretro/retroregistry.cpp index 6f4e95553..e6c34eaad 100644 --- a/source/frontends/libretro/retroregistry.cpp +++ b/source/frontends/libretro/retroregistry.cpp @@ -1,7 +1,7 @@ #include "StdAfx.h" #include "frontends/libretro/retroregistry.h" -#include "frontends/common2/ptreeregistry.h" #include "frontends/libretro/environment.h" +#include "linux/registryclass.h" #include "Common.h" #include "Card.h" @@ -173,6 +173,53 @@ namespace namespace ra2 { + class RetroRegistry : public Registry + { + public: + std::string getString(const std::string& section, const std::string& key) const override + { + const auto iter = myValues.find(section); + if (iter == myValues.end()) + throw std::runtime_error("section not found"); + + const auto iter2 = iter->second.find(key); + if (iter2 == iter->second.end()) + throw std::runtime_error("key not found"); + + return iter2->second; + } + + DWORD getDWord(const std::string& section, const std::string& key) const override + { + const std::string value = getString(section, key); + return atoi(value.c_str()); + } + + bool getBool(const std::string& section, const std::string& key) const + { + const std::string value = getString(section, key); + return (value == "true" || atoi(value.c_str()) != 0); + } + + void putString(const std::string& section, const std::string& key, const std::string& value) + { + myValues[section][key] = value; + } + + void putDWord(const std::string& section, const std::string& key, const DWORD value) + { + putString(section, key, std::to_string(value)); + } + + std::map> getAllValues() const + { + return myValues; + } + + private: + std::map> myValues; + }; + void SetupRetroVariables() { @@ -223,9 +270,10 @@ namespace ra2 } } - std::shared_ptr CreateRetroRegistry() + std::shared_ptr CreateRetroRegistry() { - const auto registry = std::make_shared(); + std::shared_ptr registry; + registry.reset(new RetroRegistry()); PopulateRegistry(registry); return registry; } diff --git a/source/frontends/libretro/retroregistry.h b/source/frontends/libretro/retroregistry.h index b1deea7c1..bdf83198a 100644 --- a/source/frontends/libretro/retroregistry.h +++ b/source/frontends/libretro/retroregistry.h @@ -8,16 +8,11 @@ class Registry; -namespace common2 -{ - class PTreeRegistry; -} - namespace ra2 { void SetupRetroVariables(); - std::shared_ptr CreateRetroRegistry(); + std::shared_ptr CreateRetroRegistry(); void PopulateRegistry(const std::shared_ptr & registry); AudioSource GetAudioSource(); diff --git a/source/frontends/libretro/serialisation.cpp b/source/frontends/libretro/serialisation.cpp index 96ea7e519..f1d5f7795 100644 --- a/source/frontends/libretro/serialisation.cpp +++ b/source/frontends/libretro/serialisation.cpp @@ -8,6 +8,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + namespace { class AutoFile @@ -25,6 +29,24 @@ namespace AutoFile::AutoFile() { +#ifdef _WIN32 + CHAR szTempFileName[MAX_PATH]; + CHAR lpTempPathBuffer[MAX_PATH]; + + DWORD dwRetVal = GetTempPathA(MAX_PATH, lpTempPathBuffer); + if (dwRetVal > MAX_PATH || (dwRetVal == 0)) + { + throw std::runtime_error("Cannot create temporary file"); + } + + UINT uRetVal = GetTempFileNameA(lpTempPathBuffer, "aws", 1, szTempFileName); + if (uRetVal == 0) + { + throw std::runtime_error("Cannot create temporary file"); + } + + myFilename = szTempFileName; +#else char pattern[] = "/tmp/awXXXXXX.aws.yaml"; myFD = mkstemps(pattern, 9); if (myFD <= 0) @@ -32,6 +54,7 @@ namespace throw std::runtime_error("Cannot create temporary file"); } myFilename = pattern; +#endif } AutoFile::~AutoFile() diff --git a/source/frontends/ncurses/world.cpp b/source/frontends/ncurses/world.cpp index 4c4230b81..1944710ab 100644 --- a/source/frontends/ncurses/world.cpp +++ b/source/frontends/ncurses/world.cpp @@ -4,7 +4,6 @@ #include #include -#include "linux/linuxinterface.h" #include "linux/keyboardbuffer.h" #include "frontends/ncurses/nframe.h" @@ -151,9 +150,3 @@ namespace na2 } } - -// Mockingboard -IDirectSoundBuffer * iCreateDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc) -{ - return nullptr; -} diff --git a/source/frontends/qt/qdirectsound.cpp b/source/frontends/qt/qdirectsound.cpp index d3da7e563..35098ebd3 100644 --- a/source/frontends/qt/qdirectsound.cpp +++ b/source/frontends/qt/qdirectsound.cpp @@ -2,7 +2,6 @@ #include "loggingcategory.h" #include "windows.h" -#include "linux/linuxinterface.h" #include #include @@ -12,12 +11,13 @@ namespace { qint64 defaultDuration = 0; - class DirectSoundGenerator : public IDirectSoundBuffer, public QIODevice + class DirectSoundGenerator : public SoundBuffer, public QIODevice { public: - DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc); + DirectSoundGenerator(); virtual ~DirectSoundGenerator() override; + virtual HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) override; virtual HRESULT Release() override; virtual HRESULT Stop() override; virtual HRESULT Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ) override; @@ -34,21 +34,26 @@ namespace std::shared_ptr myAudioOutput; }; - std::unordered_map > activeSoundGenerators; + std::unordered_map > activeSoundGenerators; - DirectSoundGenerator::DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc) - : IDirectSoundBuffer(lpcDSBufferDesc) + DirectSoundGenerator::DirectSoundGenerator() + : SoundBuffer() + { + } + + HRESULT DirectSoundGenerator::Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) { // only initialise here to skip all the buffers which are not in DSBSTATUS_PLAYING mode QAudioFormat audioFormat; - audioFormat.setSampleRate(mySampleRate); - audioFormat.setChannelCount(myChannels); - audioFormat.setSampleSize(myBitsPerSample); + audioFormat.setSampleRate(nSampleRate); + audioFormat.setChannelCount(nChannels); + audioFormat.setSampleSize(16); audioFormat.setCodec(QString::fromUtf8("audio/pcm")); audioFormat.setByteOrder(QAudioFormat::LittleEndian); audioFormat.setSampleType(QAudioFormat::SignedInt); myAudioOutput = std::make_shared(audioFormat); + return SoundBuffer::Init(dwFlags, dwBufferSize, nSampleRate, nChannels, pDevName); } DirectSoundGenerator::~DirectSoundGenerator() @@ -59,7 +64,7 @@ namespace HRESULT DirectSoundGenerator::Release() { activeSoundGenerators.erase(this); - return IUnknown::Release(); + return DS_OK; } void DirectSoundGenerator::setOptions(const qint64 duration) // in ms @@ -86,7 +91,7 @@ namespace HRESULT DirectSoundGenerator::SetVolume( LONG lVolume ) { - const HRESULT res = IDirectSoundBuffer::SetVolume(lVolume); + const HRESULT res = SoundBuffer::SetVolume(lVolume); const qreal logVolume = GetLogarithmicVolume(); const qreal linVolume = QAudio::convertVolume(logVolume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); myAudioOutput->setVolume(linVolume); @@ -95,7 +100,7 @@ namespace HRESULT DirectSoundGenerator::Stop() { - const HRESULT res = IDirectSoundBuffer::Stop(); + const HRESULT res = SoundBuffer::Stop(); myAudioOutput->stop(); QIODevice::close(); return res; @@ -103,7 +108,7 @@ namespace HRESULT DirectSoundGenerator::Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ) { - const HRESULT res = IDirectSoundBuffer::Play(dwReserved1, dwReserved2, dwFlags); + const HRESULT res = SoundBuffer::Play(dwReserved1, dwReserved2, dwFlags); QIODevice::open(ReadOnly); myAudioOutput->start(this); return res; @@ -157,23 +162,35 @@ namespace } -IDirectSoundBuffer * iCreateDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc) +static SoundBufferBase* CreateSoundBuffer(void) { try { - std::shared_ptr generator = std::make_shared(lpcDSBufferDesc); - generator->setOptions(defaultDuration); - DirectSoundGenerator * ptr = generator.get(); - activeSoundGenerators[ptr] = generator; - return ptr; + DirectSoundGenerator * generator = new DirectSoundGenerator(); + activeSoundGenerators[generator].reset(generator); + return generator; } catch (const std::exception & e) { - qDebug(appleAudio) << "IDirectSoundBuffer: " << e.what(); + qDebug(appleAudio) << "SoundBuffer: " << e.what(); return nullptr; } } +extern bool g_bDSAvailable; + +bool DSInit() +{ + SoundBufferBase::Create = CreateSoundBuffer; + g_bDSAvailable = true; + return true; +} + +void DSUninit() +{ + +} + namespace QDirectSound { diff --git a/source/frontends/sdl/sdirectsound.cpp b/source/frontends/sdl/sdirectsound.cpp index dd9d3df6a..062aabfcd 100644 --- a/source/frontends/sdl/sdirectsound.cpp +++ b/source/frontends/sdl/sdirectsound.cpp @@ -4,7 +4,6 @@ #include "frontends/common2/programoptions.h" #include "windows.h" -#include "linux/linuxinterface.h" #include "Core.h" #include "SoundCore.h" @@ -39,11 +38,12 @@ namespace return k; } - class DirectSoundGenerator : public IDirectSoundBuffer + class DirectSoundGenerator : public SoundBuffer { public: - DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc, const char * deviceName, const size_t ms); - virtual ~DirectSoundGenerator() override; + DirectSoundGenerator(); + virtual ~DirectSoundGenerator(); + virtual HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) override; virtual HRESULT Release() override; virtual HRESULT Stop() override; @@ -63,6 +63,7 @@ namespace SDL_AudioSpec myAudioSpec; size_t myBytesPerSecond; + std::string myName; uint8_t * mixBufferTo(uint8_t * stream); }; @@ -104,34 +105,41 @@ namespace } } - DirectSoundGenerator::DirectSoundGenerator(LPCDSBUFFERDESC lpcDSBufferDesc, const char * deviceName, const size_t ms) - : IDirectSoundBuffer(lpcDSBufferDesc) + DirectSoundGenerator::DirectSoundGenerator() + : SoundBuffer() , myAudioDevice(0) , myBytesPerSecond(0) + { + } + + HRESULT DirectSoundGenerator::Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) { SDL_zero(myAudioSpec); SDL_AudioSpec want; SDL_zero(want); - _ASSERT(ms > 0); + _ASSERT(audioBuffer > 0); - want.freq = mySampleRate; + want.freq = nSampleRate; want.format = AUDIO_S16LSB; - want.channels = myChannels; - want.samples = std::min(MAX_SAMPLES, nextPowerOf2(mySampleRate * ms / 1000)); + want.channels = nChannels; + want.samples = std::min(MAX_SAMPLES, nextPowerOf2(nSampleRate * audioBuffer / 1000)); want.callback = staticAudioCallback; want.userdata = this; + + const char * deviceName = audioDeviceName.empty() ? nullptr : audioDeviceName.c_str(); myAudioDevice = SDL_OpenAudioDevice(deviceName, 0, &want, &myAudioSpec, 0); if (myAudioDevice) { + myName = pDevName; myBytesPerSecond = getBytesPerSecond(myAudioSpec); + return SoundBuffer::Init(dwFlags, dwBufferSize, nSampleRate, nChannels, pDevName); } - else - { - throw std::runtime_error(sa2::decorateSDLError("SDL_OpenAudioDevice")); - } + + LogOutput("DirectSoundGenerator: %s\n", sa2::decorateSDLError("SDL_OpenAudioDevice").c_str()); + return E_FAIL; } DirectSoundGenerator::~DirectSoundGenerator() @@ -143,19 +151,19 @@ namespace HRESULT DirectSoundGenerator::Release() { activeSoundGenerators.erase(this); // this will force the destructor - return IUnknown::Release(); + return DS_OK; } HRESULT DirectSoundGenerator::Stop() { - const HRESULT res = IDirectSoundBuffer::Stop(); + const HRESULT res = SoundBuffer::Stop(); SDL_PauseAudioDevice(myAudioDevice, 1); return res; } HRESULT DirectSoundGenerator::Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ) { - const HRESULT res = IDirectSoundBuffer::Play(dwReserved1, dwReserved2, dwFlags); + const HRESULT res = SoundBuffer::Play(dwReserved1, dwReserved2, dwFlags); SDL_PauseAudioDevice(myAudioDevice, 0); return res; } @@ -209,27 +217,37 @@ namespace } -IDirectSoundBuffer * iCreateDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc) +static SoundBufferBase* CreateSoundBuffer(void) { try { - const char * deviceName = audioDeviceName.empty() ? nullptr : audioDeviceName.c_str(); - - std::shared_ptr generator = std::make_shared(lpcDSBufferDesc, deviceName, audioBuffer); - DirectSoundGenerator * ptr = generator.get(); - activeSoundGenerators[ptr] = generator; - return ptr; + DirectSoundGenerator * generator = new DirectSoundGenerator(); + activeSoundGenerators[generator].reset(generator); + return generator; } catch (const std::exception & e) { - // once this fails, no point in trying again next time g_bDisableDirectSound = true; g_bDisableDirectSoundMockingboard = true; - LogOutput("IDirectSoundBuffer: %s\n", e.what()); + LogOutput("SoundBuffer: %s\n", e.what()); return nullptr; } } +extern bool g_bDSAvailable; + +bool DSInit() +{ + SoundBufferBase::Create = CreateSoundBuffer; + g_bDSAvailable = true; + return true; +} + +void DSUninit() +{ + +} + namespace sa2 { diff --git a/source/frontends/sdl/sdlframe.cpp b/source/frontends/sdl/sdlframe.cpp index de3a7156d..963d61371 100644 --- a/source/frontends/sdl/sdlframe.cpp +++ b/source/frontends/sdl/sdlframe.cpp @@ -212,6 +212,15 @@ namespace sa2 return myWindow; } + static std::string getBitmapFilename(const std::string & resource) + { + if (resource == "CHARSET82") return "CHARSET82.bmp"; + if (resource == "CHARSET8M") return "CHARSET8M.bmp"; + if (resource == "CHARSET8C") return "CHARSET8C.bmp"; + + return resource; + } + void SDLFrame::GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) { const std::string filename = getBitmapFilename(lpBitmapName); diff --git a/source/linux/duplicates/SerialComms.cpp b/source/linux/duplicates/SerialComms.cpp index db0936b35..945f96d07 100644 --- a/source/linux/duplicates/SerialComms.cpp +++ b/source/linux/duplicates/SerialComms.cpp @@ -3,7 +3,6 @@ #include "SerialComms.h" #include "YamlHelper.h" - CSuperSerialCard::CSuperSerialCard(UINT slot) : Card(CT_SSC, slot) { diff --git a/source/linux/libwindows/CMakeLists.txt b/source/linux/libwindows/CMakeLists.txt index 57a287052..a3db0134d 100644 --- a/source/linux/libwindows/CMakeLists.txt +++ b/source/linux/libwindows/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SOURCE_FILES +set(SOURCE_FILES ${SOURCE_FILES} dmusicc.cpp dsound.cpp fileapi.cpp @@ -13,7 +13,7 @@ set(SOURCE_FILES winuser.cpp ) -set(HEADER_FILES +set(HEADER_FILES ${HEADER_FILES} dmusicc.h dsound.h fileapi.h @@ -44,3 +44,8 @@ add_library(windows STATIC target_include_directories(windows PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) + +# dsound.cpp depends on soundbuffer.cpp +target_link_libraries(windows PRIVATE + appleii + ) \ No newline at end of file diff --git a/source/linux/libwindows/dsound.cpp b/source/linux/libwindows/dsound.cpp index 922da533f..a48a226cf 100644 --- a/source/linux/libwindows/dsound.cpp +++ b/source/linux/libwindows/dsound.cpp @@ -1,210 +1,23 @@ #include "dsound.h" -#include "linux/linuxinterface.h" -#include - -IDirectSoundBuffer::IDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc) - : mySoundBuffer(lpcDSBufferDesc->dwBufferBytes) - , myNumberOfUnderruns(0) - , myBufferSize(lpcDSBufferDesc->dwBufferBytes) - , mySampleRate(lpcDSBufferDesc->lpwfxFormat->nSamplesPerSec) - , myChannels(lpcDSBufferDesc->lpwfxFormat->nChannels) - , myBitsPerSample(lpcDSBufferDesc->lpwfxFormat->wBitsPerSample) - , myFlags(lpcDSBufferDesc->dwFlags) - , myName(lpcDSBufferDesc->szName) -{ -} - -HRESULT IDirectSoundBuffer::Unlock( LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2 ) -{ - const size_t totalWrittenBytes = dwAudioBytes1 + dwAudioBytes2; - this->myWritePosition = (this->myWritePosition + totalWrittenBytes) % this->mySoundBuffer.size(); - myMutex.unlock(); - return DS_OK; -} - -HRESULT IDirectSoundBuffer::Stop() -{ - const DWORD mask = DSBSTATUS_PLAYING | DSBSTATUS_LOOPING; - this->myStatus &= ~mask; - return DS_OK; -} - -HRESULT IDirectSoundBuffer::SetCurrentPosition( DWORD dwNewPosition ) -{ - return DS_OK; -} - -HRESULT IDirectSoundBuffer::Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ) -{ - this->myStatus |= DSBSTATUS_PLAYING; - if (dwFlags & DSBPLAY_LOOPING) - { - this->myStatus |= DSBSTATUS_LOOPING; - } - return S_OK; -} +#include "linux/soundbuffer.h" -HRESULT IDirectSoundBuffer::SetVolume( LONG lVolume ) -{ - this->myVolume = lVolume; - return DS_OK; -} - -HRESULT IDirectSoundBuffer::GetStatus( LPDWORD lpdwStatus ) -{ - *lpdwStatus = this->myStatus; - return DS_OK; -} - -HRESULT IDirectSoundBuffer::Restore() -{ - return DS_OK; -} - -HRESULT IDirectSoundBuffer::Lock( DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2, DWORD dwFlags ) -{ - myMutex.lock(); - // No attempt is made at restricting write buffer not to overtake play cursor - if (dwFlags & DSBLOCK_ENTIREBUFFER) - { - *lplpvAudioPtr1 = this->mySoundBuffer.data(); - *lpdwAudioBytes1 = this->mySoundBuffer.size(); - if (lplpvAudioPtr2 && lpdwAudioBytes2) - { - *lplpvAudioPtr2 = nullptr; - *lpdwAudioBytes2 = 0; - } - } - else - { - const DWORD availableInFirstPart = this->mySoundBuffer.size() - dwWriteCursor; - - *lplpvAudioPtr1 = this->mySoundBuffer.data() + dwWriteCursor; - *lpdwAudioBytes1 = std::min(availableInFirstPart, dwWriteBytes); - - if (lplpvAudioPtr2 && lpdwAudioBytes2) - { - if (*lpdwAudioBytes1 < dwWriteBytes) - { - *lplpvAudioPtr2 = this->mySoundBuffer.data(); - *lpdwAudioBytes2 = std::min(dwWriteCursor, dwWriteBytes - *lpdwAudioBytes1); - } - else - { - *lplpvAudioPtr2 = nullptr; - *lpdwAudioBytes2 = 0; - } - } - } - - return DS_OK; -} - -DWORD IDirectSoundBuffer::Read( DWORD dwReadBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2) -{ - const std::lock_guard guard(myMutex); - - // Read up to dwReadBytes, never going past the write cursor - // Positions are updated immediately - const DWORD available = (this->myWritePosition - this->myPlayPosition) % this->myBufferSize; - if (available < dwReadBytes) - { - dwReadBytes = available; - ++myNumberOfUnderruns; - } - - const DWORD availableInFirstPart = this->mySoundBuffer.size() - this->myPlayPosition; - - *lplpvAudioPtr1 = this->mySoundBuffer.data() + this->myPlayPosition; - *lpdwAudioBytes1 = std::min(availableInFirstPart, dwReadBytes); - - if (lplpvAudioPtr2 && lpdwAudioBytes2) - { - if (*lpdwAudioBytes1 < dwReadBytes) - { - *lplpvAudioPtr2 = this->mySoundBuffer.data(); - *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1; - } - else - { - *lplpvAudioPtr2 = nullptr; - *lpdwAudioBytes2 = 0; - } - } - this->myPlayPosition = (this->myPlayPosition + dwReadBytes) % this->mySoundBuffer.size(); - return dwReadBytes; -} - -DWORD IDirectSoundBuffer::GetBytesInBuffer() -{ - const std::lock_guard guard(myMutex); - const DWORD available = (this->myWritePosition - this->myPlayPosition) % this->myBufferSize; - return available; -} - -HRESULT IDirectSoundBuffer::GetCurrentPosition( LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor ) -{ - *lpdwCurrentPlayCursor = this->myPlayPosition; - *lpdwCurrentWriteCursor = this->myWritePosition; - return DS_OK; -} - -HRESULT IDirectSoundBuffer::GetVolume( LONG * lplVolume ) -{ - *lplVolume = this->myVolume; - return DS_OK; -} - -double IDirectSoundBuffer::GetLogarithmicVolume() const -{ - const double volume = (double(myVolume) - DSBVOLUME_MIN) / (0.0 - DSBVOLUME_MIN); - return volume; -} - -size_t IDirectSoundBuffer::GetBufferUnderruns() const -{ - return myNumberOfUnderruns; -} - -void IDirectSoundBuffer::ResetUnderruns() -{ - myNumberOfUnderruns = 0; -} - -HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter) -{ - *ppDS = new IDirectSound(); - return DS_OK; -} +#include -HRESULT DirectSoundEnumerate(LPDSENUMCALLBACK lpDSEnumCallback, LPVOID lpContext) +static SoundBufferBase* CreateSoundBuffer(void) { - GUID guid = 123; - lpDSEnumCallback(&guid, "audio", "linux", lpContext); - return DS_OK; + return new SoundBuffer(); } -HRESULT IDirectSound::CreateSoundBuffer( LPCDSBUFFERDESC lpcDSBufferDesc, IDirectSoundBuffer **lplpDirectSoundBuffer, IUnknown FAR* pUnkOuter ) -{ - if (*lplpDirectSoundBuffer) - { - (*lplpDirectSoundBuffer)->Release(); - } - - IDirectSoundBuffer * dsb = iCreateDirectSoundBuffer(lpcDSBufferDesc); - - *lplpDirectSoundBuffer = dsb; - return dsb ? DS_OK : DSERR_GENERIC; -} +extern bool g_bDSAvailable; -HRESULT IDirectSound::SetCooperativeLevel( HWND hwnd, DWORD dwLevel ) +bool DSInit() { - return DS_OK; + SoundBufferBase::Create = CreateSoundBuffer; + g_bDSAvailable = true; + return true; } -HRESULT IDirectSound::GetCaps(LPDSCCAPS pDSCCaps) +void DSUninit() { - memset(pDSCCaps, 0, sizeof(*pDSCCaps)); - return DS_OK; } diff --git a/source/linux/libwindows/dsound.h b/source/linux/libwindows/dsound.h index aaebd0ec4..00a82ba34 100644 --- a/source/linux/libwindows/dsound.h +++ b/source/linux/libwindows/dsound.h @@ -4,6 +4,7 @@ #include "winerror.h" #include "mmreg.h" #include "guiddef.h" +#include "linux/soundbuffer.h" #include #include @@ -53,7 +54,6 @@ #define DSSCL_NORMAL 1 typedef BOOL (CALLBACK *LPDSENUMCALLBACK)(LPGUID,LPCSTR,LPCSTR,LPVOID); - HRESULT DirectSoundEnumerate(LPDSENUMCALLBACK lpDSEnumCallback, LPVOID lpContext); typedef struct { @@ -62,7 +62,6 @@ typedef struct { DWORD dwFormats; DWORD dwChannels; } DSCCAPS, DSCAPS, *LPDSCCAPS; - typedef const DSCCAPS *LPCDSCCAPS; typedef struct _DSBUFFERDESC @@ -73,7 +72,6 @@ typedef struct _DSBUFFERDESC DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; GUID guid3DAlgorithm; - LPCSTR szName; // only in the linux version to differentiate the channels } DSBUFFERDESC,*LPDSBUFFERDESC; typedef const DSBUFFERDESC *LPCDSBUFFERDESC; @@ -89,56 +87,11 @@ struct IDirectSoundNotify }; typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY,**LPLPDIRECTSOUNDNOTIFY; -class IDirectSoundBuffer : public IUnknown -{ - std::vector mySoundBuffer; - - size_t myPlayPosition = 0; - size_t myWritePosition = 0; - WORD myStatus = 0; - LONG myVolume = DSBVOLUME_MAX; - - // updated by the callback - std::atomic_size_t myNumberOfUnderruns; - std::mutex myMutex; - -public: - const size_t myBufferSize; - const size_t mySampleRate; - const size_t myChannels; - const size_t myBitsPerSample; - const size_t myFlags; - const std::string myName; - - IDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc); - - HRESULT SetCurrentPosition( DWORD dwNewPosition ); - HRESULT GetCurrentPosition( LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor ); - - HRESULT Lock( DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2, DWORD dwFlags ); - virtual HRESULT Unlock( LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2 ); - - virtual HRESULT Stop(); - virtual HRESULT Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ); - - virtual HRESULT SetVolume( LONG lVolume ); - HRESULT GetVolume( LONG * lplVolume ); - - HRESULT GetStatus( LPDWORD lpdwStatus ); - HRESULT Restore(); - - // NOT part of Windows API - DWORD Read( DWORD dwReadBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2); - DWORD GetBytesInBuffer(); - size_t GetBufferUnderruns() const; - void ResetUnderruns(); - double GetLogarithmicVolume() const; // in [0, 1] -}; -typedef class IDirectSoundBuffer *LPDIRECTSOUNDBUFFER,**LPLPDIRECTSOUNDBUFFER; +typedef class SoundBuffer *LPDIRECTSOUNDBUFFER,**LPLPDIRECTSOUNDBUFFER; struct IDirectSound : public IAutoRelease { - HRESULT CreateSoundBuffer( LPCDSBUFFERDESC lpcDSBufferDesc, IDirectSoundBuffer **lplpDirectSoundBuffer, IUnknown FAR* pUnkOuter ); + HRESULT CreateSoundBuffer( LPCDSBUFFERDESC lpcDSBufferDesc, LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer, IUnknown FAR* pUnkOuter ); int i; HRESULT SetCooperativeLevel( HWND hwnd, DWORD dwLevel ); HRESULT GetCaps(LPDSCCAPS pDSCCaps); }; diff --git a/source/linux/libwindows/wincompat.h b/source/linux/libwindows/wincompat.h index e3aa7a494..26a6fb1ee 100644 --- a/source/linux/libwindows/wincompat.h +++ b/source/linux/libwindows/wincompat.h @@ -44,7 +44,9 @@ typedef uint16_t UINT16; // // we stick to VS's definition // this is important when selecting the correct printf format specifier +#ifndef __int64 #define __int64 long long int +#endif typedef intptr_t INT_PTR; typedef uintptr_t UINT_PTR; @@ -190,7 +192,9 @@ typedef unsigned char TBYTE , *PTBYTE ; #define TEXT(quote) __TEXT(quote) // r_winnt #define WINAPI +#ifndef __stdcall #define __stdcall +#endif #define CALLBACK #ifdef _DEBUG @@ -200,7 +204,9 @@ typedef unsigned char TBYTE , *PTBYTE ; #endif #define __interface struct +#ifndef __forceinline #define __forceinline inline +#endif #define _tmain main diff --git a/source/linux/linuxframe.cpp b/source/linux/linuxframe.cpp index 09989bcaa..33ce899a1 100644 --- a/source/linux/linuxframe.cpp +++ b/source/linux/linuxframe.cpp @@ -1,7 +1,9 @@ #include "StdAfx.h" #include "linux/linuxframe.h" #include "linux/context.h" +#ifndef _WIN32 #include "linux/network/slirp2.h" +#endif #include "linux/version.h" #include "Interface.h" #include "Log.h" @@ -66,7 +68,7 @@ LinuxFrame::LinuxFrame(const bool autoBoot) : myAutoBoot(autoBoot) { const std::array version = getVersionNumbers(); SetAppleWinVersion(version[0], version[1], version[2], version[3]); - g_hFrameWindow = this; + g_hFrameWindow = (HWND)this; } void LinuxFrame::Initialize(bool resetVideoState) @@ -153,14 +155,20 @@ void LinuxFrame::LoadSnapshot() std::shared_ptr LinuxFrame::CreateNetworkBackend(const std::string & interfaceName) { -#ifdef U2_USE_SLIRP +#ifndef _WIN32 + #ifdef U2_USE_SLIRP return std::make_shared(); -#else + #else return std::make_shared(interfaceName); + #endif +#else + return std::shared_ptr(); #endif } +#ifndef _WIN32 int MessageBox(HWND, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { return GetFrame().FrameMessageBox(lpText, lpCaption, uType); } +#endif \ No newline at end of file diff --git a/source/linux/linuxframe.h b/source/linux/linuxframe.h index 499b5ab49..dfc582a4e 100644 --- a/source/linux/linuxframe.h +++ b/source/linux/linuxframe.h @@ -51,4 +51,6 @@ class LinuxFrame : public FrameBase bool myAutoBoot; // non const to allow settings change }; +#ifndef _WIN32 int MessageBox(HWND, LPCSTR lpText, LPCSTR lpCaption, UINT uType); +#endif \ No newline at end of file diff --git a/source/linux/linuxinterface.h b/source/linux/linuxinterface.h deleted file mode 100644 index 4750098ee..000000000 --- a/source/linux/linuxinterface.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -class IDirectSoundBuffer; - -// Sound -IDirectSoundBuffer * iCreateDirectSoundBuffer(LPCDSBUFFERDESC lpcDSBufferDesc); diff --git a/source/linux/registryclass.cpp b/source/linux/registryclass.cpp index f7d493a2f..ac6975489 100644 --- a/source/linux/registryclass.cpp +++ b/source/linux/registryclass.cpp @@ -1,3 +1,5 @@ +#include "StdAfx.h" + #include "registryclass.h" #include "windows.h" #include "Log.h" diff --git a/source/linux/registryclass.h b/source/linux/registryclass.h index 81df926e4..e5bcaf6a6 100644 --- a/source/linux/registryclass.h +++ b/source/linux/registryclass.h @@ -1,6 +1,9 @@ #pragma once -#include "wincompat.h" +#ifndef _WIN32 +#include "linux/libwindows/wincompat.h" +#endif + #include #include #include diff --git a/source/linux/soundbuffer.cpp b/source/linux/soundbuffer.cpp new file mode 100644 index 000000000..6eb4b81fe --- /dev/null +++ b/source/linux/soundbuffer.cpp @@ -0,0 +1,176 @@ +#include + +#include "soundbuffer.h" + +HRESULT SoundBuffer::Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) +{ + myBufferSize = dwBufferSize; + mySoundBuffer.resize(dwBufferSize); + myNumberOfUnderruns = 0; + mySampleRate = nSampleRate; + myChannels = nChannels; + + return DS_OK; +} + +HRESULT SoundBuffer::Release() +{ + return DS_OK; +} + +HRESULT SoundBuffer::Unlock( LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2 ) +{ + const size_t totalWrittenBytes = dwAudioBytes1 + dwAudioBytes2; + this->myWritePosition = (this->myWritePosition + totalWrittenBytes) % this->mySoundBuffer.size(); + myMutex.unlock(); + return DS_OK; +} + +HRESULT SoundBuffer::Stop() +{ + const DWORD mask = DSBSTATUS_PLAYING | DSBSTATUS_LOOPING; + this->myStatus &= ~mask; + return DS_OK; +} + +HRESULT SoundBuffer::SetCurrentPosition( DWORD dwNewPosition ) +{ + return DS_OK; +} + +HRESULT SoundBuffer::Play( DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags ) +{ + this->myStatus |= DSBSTATUS_PLAYING; + if (dwFlags & DSBPLAY_LOOPING) + { + this->myStatus |= DSBSTATUS_LOOPING; + } + return S_OK; +} + +HRESULT SoundBuffer::SetVolume( LONG lVolume ) +{ + this->myVolume = lVolume; + return DS_OK; +} + +HRESULT SoundBuffer::GetStatus( LPDWORD lpdwStatus ) +{ + *lpdwStatus = this->myStatus; + return DS_OK; +} + +HRESULT SoundBuffer::Restore() +{ + return DS_OK; +} + +HRESULT SoundBuffer::Lock( DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2, DWORD dwFlags ) +{ + myMutex.lock(); + // No attempt is made at restricting write buffer not to overtake play cursor + if (dwFlags & DSBLOCK_ENTIREBUFFER) + { + *lplpvAudioPtr1 = this->mySoundBuffer.data(); + *lpdwAudioBytes1 = this->mySoundBuffer.size(); + if (lplpvAudioPtr2 && lpdwAudioBytes2) + { + *lplpvAudioPtr2 = nullptr; + *lpdwAudioBytes2 = 0; + } + } + else + { + const DWORD availableInFirstPart = this->mySoundBuffer.size() - dwWriteCursor; + + *lplpvAudioPtr1 = this->mySoundBuffer.data() + dwWriteCursor; + *lpdwAudioBytes1 = std::min(availableInFirstPart, dwWriteBytes); + + if (lplpvAudioPtr2 && lpdwAudioBytes2) + { + if (*lpdwAudioBytes1 < dwWriteBytes) + { + *lplpvAudioPtr2 = this->mySoundBuffer.data(); + *lpdwAudioBytes2 = std::min(dwWriteCursor, dwWriteBytes - *lpdwAudioBytes1); + } + else + { + *lplpvAudioPtr2 = nullptr; + *lpdwAudioBytes2 = 0; + } + } + } + + return DS_OK; +} + +DWORD SoundBuffer::Read( DWORD dwReadBytes, LPVOID * lplpvAudioPtr1, DWORD * lpdwAudioBytes1, LPVOID * lplpvAudioPtr2, DWORD * lpdwAudioBytes2) +{ + const std::lock_guard guard(myMutex); + + // Read up to dwReadBytes, never going past the write cursor + // Positions are updated immediately + const DWORD available = (this->myWritePosition - this->myPlayPosition) % this->myBufferSize; + if (available < dwReadBytes) + { + dwReadBytes = available; + ++myNumberOfUnderruns; + } + + const DWORD availableInFirstPart = this->mySoundBuffer.size() - this->myPlayPosition; + + *lplpvAudioPtr1 = this->mySoundBuffer.data() + this->myPlayPosition; + *lpdwAudioBytes1 = std::min(availableInFirstPart, dwReadBytes); + + if (lplpvAudioPtr2 && lpdwAudioBytes2) + { + if (*lpdwAudioBytes1 < dwReadBytes) + { + *lplpvAudioPtr2 = this->mySoundBuffer.data(); + *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1; + } + else + { + *lplpvAudioPtr2 = nullptr; + *lpdwAudioBytes2 = 0; + } + } + this->myPlayPosition = (this->myPlayPosition + dwReadBytes) % this->mySoundBuffer.size(); + return dwReadBytes; +} + +DWORD SoundBuffer::GetBytesInBuffer() +{ + const std::lock_guard guard(myMutex); + const DWORD available = (this->myWritePosition - this->myPlayPosition) % this->myBufferSize; + return available; +} + +HRESULT SoundBuffer::GetCurrentPosition( LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor ) +{ + *lpdwCurrentPlayCursor = this->myPlayPosition; + *lpdwCurrentWriteCursor = this->myWritePosition; + return DS_OK; +} + +HRESULT SoundBuffer::GetVolume( LONG * lplVolume ) +{ + *lplVolume = this->myVolume; + return DS_OK; +} + +double SoundBuffer::GetLogarithmicVolume() const +{ + const double volume = (double(myVolume) - DSBVOLUME_MIN) / (0.0 - DSBVOLUME_MIN); + return volume; +} + +size_t SoundBuffer::GetBufferUnderruns() const +{ + return myNumberOfUnderruns; +} + +void SoundBuffer::ResetUnderruns() +{ + myNumberOfUnderruns = 0; +} diff --git a/source/linux/soundbuffer.h b/source/linux/soundbuffer.h new file mode 100644 index 000000000..17b450f18 --- /dev/null +++ b/source/linux/soundbuffer.h @@ -0,0 +1,52 @@ +#pragma once + +#include "SoundBufferBase.h" + +#include +#include +#include + +class SoundBuffer : public SoundBufferBase +{ +private: + std::vector mySoundBuffer; + + size_t myPlayPosition = 0; + size_t myWritePosition = 0; + WORD myStatus = 0; + LONG myVolume = 0; + + // updated by the callback + std::atomic_size_t myNumberOfUnderruns; + std::mutex myMutex; + +public: + size_t myBufferSize; + size_t mySampleRate; + size_t myChannels; + size_t myBitsPerSample; + + HRESULT Init(DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels, LPCSTR pDevName) override; + HRESULT Release() override; + + HRESULT SetCurrentPosition(DWORD dwNewPosition) override; + HRESULT GetCurrentPosition(LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor) override; + + HRESULT Lock(DWORD dwWriteCursor, DWORD dwWriteBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2, DWORD dwFlags) override; + virtual HRESULT Unlock(LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2) override; + + virtual HRESULT Stop() override; + virtual HRESULT Play(DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags) override; + + virtual HRESULT SetVolume(LONG lVolume) override; + HRESULT GetVolume(LONG* lplVolume) override; + + HRESULT GetStatus(LPDWORD lpdwStatus) override; + HRESULT Restore() override; + + DWORD Read(DWORD dwReadBytes, LPVOID* lplpvAudioPtr1, DWORD* lpdwAudioBytes1, LPVOID* lplpvAudioPtr2, DWORD* lpdwAudioBytes2); + DWORD GetBytesInBuffer(); + size_t GetBufferUnderruns() const; + void ResetUnderruns(); + double GetLogarithmicVolume() const; // in [0, 1] +}; \ No newline at end of file diff --git a/test/TestCPU6502/CMakeLists.txt b/test/TestCPU6502/CMakeLists.txt index b55f05544..5c8068b2b 100644 --- a/test/TestCPU6502/CMakeLists.txt +++ b/test/TestCPU6502/CMakeLists.txt @@ -3,5 +3,7 @@ add_executable(testcpu6502 ../../source/SynchronousEventManager.cpp TestCPU6502.cpp) +if(NOT WIN32) target_link_libraries(testcpu6502 windows) +endif() \ No newline at end of file diff --git a/test/TestCPU6502/stdafx.h b/test/TestCPU6502/stdafx.h index d8f8be361..560d2c20c 100644 --- a/test/TestCPU6502/stdafx.h +++ b/test/TestCPU6502/stdafx.h @@ -5,12 +5,14 @@ #pragma once -#ifdef _MSC_VER +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include #include #include - -#include +#include #if _MSC_VER >= 1600 // supported from VS2010 (cl.exe v16.00) #include // cleanup WORD DWORD -> uint16_t uint32_t @@ -24,11 +26,11 @@ typedef UINT64 uint64_t; #include -#else +#else // !_WIN32 #include #include #include "windows.h" #include -#endif +#endif // _WIN32