mac fix
This commit is contained in:
@ -132,6 +132,10 @@ target_link_libraries(tetris PRIVATE SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::S
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(tetris PRIVATE mfplat mfreadwrite mfuuid)
|
target_link_libraries(tetris PRIVATE mfplat mfreadwrite mfuuid)
|
||||||
endif()
|
endif()
|
||||||
|
if(APPLE)
|
||||||
|
# Needed for MP3 decoding via AudioToolbox on macOS
|
||||||
|
target_link_libraries(tetris PRIVATE "-framework AudioToolbox" "-framework CoreFoundation")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Include production build configuration
|
# Include production build configuration
|
||||||
include(cmake/ProductionBuild.cmake)
|
include(cmake/ProductionBuild.cmake)
|
||||||
|
|||||||
@ -26,6 +26,9 @@ using Microsoft::WRL::ComPtr;
|
|||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Audio& Audio::instance(){ static Audio inst; return inst; }
|
Audio& Audio::instance(){ static Audio inst; return inst; }
|
||||||
@ -36,7 +39,7 @@ bool Audio::init(){ if(outSpec.freq!=0) return true; outSpec.format=SDL_AUDIO_S1
|
|||||||
#endif
|
#endif
|
||||||
return true; }
|
return true; }
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
static bool decodeMP3(const std::string& path, std::vector<int16_t>& outPCM, int& outRate, int& outCh){
|
static bool decodeMP3(const std::string& path, std::vector<int16_t>& outPCM, int& outRate, int& outCh){
|
||||||
outPCM.clear(); outRate=44100; outCh=2;
|
outPCM.clear(); outRate=44100; outCh=2;
|
||||||
ComPtr<IMFSourceReader> reader;
|
ComPtr<IMFSourceReader> reader;
|
||||||
@ -47,15 +50,85 @@ static bool decodeMP3(const std::string& path, std::vector<int16_t>& outPCM, int
|
|||||||
reader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
|
reader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
|
||||||
while(true){ DWORD flags=0; ComPtr<IMFSample> sample; if(FAILED(reader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,0,nullptr,&flags,nullptr,&sample))) break; if(flags & MF_SOURCE_READERF_ENDOFSTREAM) break; if(!sample) continue; ComPtr<IMFMediaBuffer> buffer; if(FAILED(sample->ConvertToContiguousBuffer(&buffer))) continue; BYTE* data=nullptr; DWORD maxLen=0, curLen=0; if(SUCCEEDED(buffer->Lock(&data,&maxLen,&curLen)) && curLen){ size_t samples = curLen/2; size_t oldSz = outPCM.size(); outPCM.resize(oldSz + samples); std::memcpy(outPCM.data()+oldSz, data, curLen); } if(data) buffer->Unlock(); }
|
while(true){ DWORD flags=0; ComPtr<IMFSample> sample; if(FAILED(reader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,0,nullptr,&flags,nullptr,&sample))) break; if(flags & MF_SOURCE_READERF_ENDOFSTREAM) break; if(!sample) continue; ComPtr<IMFMediaBuffer> buffer; if(FAILED(sample->ConvertToContiguousBuffer(&buffer))) continue; BYTE* data=nullptr; DWORD maxLen=0, curLen=0; if(SUCCEEDED(buffer->Lock(&data,&maxLen,&curLen)) && curLen){ size_t samples = curLen/2; size_t oldSz = outPCM.size(); outPCM.resize(oldSz + samples); std::memcpy(outPCM.data()+oldSz, data, curLen); } if(data) buffer->Unlock(); }
|
||||||
outRate=44100; outCh=2; return !outPCM.empty(); }
|
outRate=44100; outCh=2; return !outPCM.empty(); }
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
// Decode MP3 files using macOS AudioToolbox so music works on Apple builds.
|
||||||
|
static bool decodeMP3(const std::string& path, std::vector<int16_t>& outPCM, int& outRate, int& outCh){
|
||||||
|
outPCM.clear();
|
||||||
|
outRate = 44100;
|
||||||
|
outCh = 2;
|
||||||
|
|
||||||
|
CFURLRef url = CFURLCreateFromFileSystemRepresentation(nullptr, reinterpret_cast<const UInt8*>(path.c_str()), path.size(), false);
|
||||||
|
if (!url) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to create URL for %s", path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtAudioFileRef audioFile = nullptr;
|
||||||
|
OSStatus status = ExtAudioFileOpenURL(url, &audioFile);
|
||||||
|
CFRelease(url);
|
||||||
|
if (status != noErr || !audioFile) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] ExtAudioFileOpenURL failed (%d) for %s", static_cast<int>(status), path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioStreamBasicDescription clientFormat{};
|
||||||
|
clientFormat.mSampleRate = 44100.0;
|
||||||
|
clientFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
clientFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||||
|
clientFormat.mBitsPerChannel = 16;
|
||||||
|
clientFormat.mChannelsPerFrame = 2;
|
||||||
|
clientFormat.mFramesPerPacket = 1;
|
||||||
|
clientFormat.mBytesPerFrame = (clientFormat.mBitsPerChannel / 8) * clientFormat.mChannelsPerFrame;
|
||||||
|
clientFormat.mBytesPerPacket = clientFormat.mBytesPerFrame * clientFormat.mFramesPerPacket;
|
||||||
|
|
||||||
|
status = ExtAudioFileSetProperty(audioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);
|
||||||
|
if (status != noErr) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to set client format (%d) for %s", static_cast<int>(status), path.c_str());
|
||||||
|
ExtAudioFileDispose(audioFile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UInt32 framesPerBuffer = 4096;
|
||||||
|
std::vector<int16_t> buffer(framesPerBuffer * clientFormat.mChannelsPerFrame);
|
||||||
|
while (true) {
|
||||||
|
AudioBufferList abl{};
|
||||||
|
abl.mNumberBuffers = 1;
|
||||||
|
abl.mBuffers[0].mNumberChannels = clientFormat.mChannelsPerFrame;
|
||||||
|
abl.mBuffers[0].mDataByteSize = framesPerBuffer * clientFormat.mBytesPerFrame;
|
||||||
|
abl.mBuffers[0].mData = buffer.data();
|
||||||
|
|
||||||
|
UInt32 framesToRead = framesPerBuffer;
|
||||||
|
status = ExtAudioFileRead(audioFile, &framesToRead, &abl);
|
||||||
|
if (status != noErr) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] ExtAudioFileRead failed (%d) for %s", static_cast<int>(status), path.c_str());
|
||||||
|
ExtAudioFileDispose(audioFile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (framesToRead == 0) {
|
||||||
|
break; // EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t samplesRead = static_cast<size_t>(framesToRead) * clientFormat.mChannelsPerFrame;
|
||||||
|
outPCM.insert(outPCM.end(), buffer.data(), buffer.data() + samplesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtAudioFileDispose(audioFile);
|
||||||
|
outRate = static_cast<int>(clientFormat.mSampleRate);
|
||||||
|
outCh = static_cast<int>(clientFormat.mChannelsPerFrame);
|
||||||
|
return !outPCM.empty();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static bool decodeMP3(const std::string& path, std::vector<int16_t>& outPCM, int& outRate, int& outCh){
|
||||||
|
(void)outPCM; (void)outRate; (void)outCh; (void)path;
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] MP3 unsupported on this platform: %s", path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Audio::addTrack(const std::string& path){ AudioTrack t; t.path=path;
|
void Audio::addTrack(const std::string& path){ AudioTrack t; t.path=path;
|
||||||
#ifdef _WIN32
|
if(decodeMP3(path, t.pcm, t.rate, t.channels)) t.ok=true; else SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode %s", path.c_str());
|
||||||
if(decodeMP3(path, t.pcm, t.rate, t.channels)) t.ok=true; else SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode %s", path.c_str());
|
tracks.push_back(std::move(t)); }
|
||||||
#else
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] MP3 unsupported on this platform (stub): %s", path.c_str());
|
|
||||||
#endif
|
|
||||||
tracks.push_back(std::move(t)); }
|
|
||||||
|
|
||||||
void Audio::shuffle(){
|
void Audio::shuffle(){
|
||||||
std::lock_guard<std::mutex> lock(tracksMutex);
|
std::lock_guard<std::mutex> lock(tracksMutex);
|
||||||
@ -252,15 +325,11 @@ void Audio::backgroundLoadingThread() {
|
|||||||
}
|
}
|
||||||
AudioTrack t;
|
AudioTrack t;
|
||||||
t.path = path;
|
t.path = path;
|
||||||
#ifdef _WIN32
|
if (decodeMP3(path, t.pcm, t.rate, t.channels)) {
|
||||||
if (mfInitialized && decodeMP3(path, t.pcm, t.rate, t.channels)) {
|
|
||||||
t.ok = true;
|
t.ok = true;
|
||||||
} else {
|
} else {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode %s", path.c_str());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode %s", path.c_str());
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] MP3 unsupported on this platform (stub): %s", path.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Thread-safe addition to tracks
|
// Thread-safe addition to tracks
|
||||||
if (loadingAbort.load()) {
|
if (loadingAbort.load()) {
|
||||||
@ -311,18 +380,11 @@ int Audio::getLoadedTrackCount() const {
|
|||||||
|
|
||||||
void Audio::setMenuTrack(const std::string& path) {
|
void Audio::setMenuTrack(const std::string& path) {
|
||||||
menuTrack.path = path;
|
menuTrack.path = path;
|
||||||
#ifdef _WIN32
|
|
||||||
// Ensure MF is started (might be redundant if init called, but safe)
|
|
||||||
if(!mfStarted){ if(FAILED(MFStartup(MF_VERSION))) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] MFStartup failed"); } else mfStarted=true; }
|
|
||||||
|
|
||||||
if (decodeMP3(path, menuTrack.pcm, menuTrack.rate, menuTrack.channels)) {
|
if (decodeMP3(path, menuTrack.pcm, menuTrack.rate, menuTrack.channels)) {
|
||||||
menuTrack.ok = true;
|
menuTrack.ok = true;
|
||||||
} else {
|
} else {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode menu track %s", path.c_str());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] Failed to decode menu track %s", path.c_str());
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[Audio] MP3 unsupported (stub): %s", path.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::playMenuMusic() {
|
void Audio::playMenuMusic() {
|
||||||
|
|||||||
Reference in New Issue
Block a user