// Diese Datei ist stark an den examples von miniaudio orientiert (vor allem simple_mixing.c). Die Struktur ähnelt sich daher möglicherweise. //#define MA_DEBUG_OUTPUT //#define MA_LOG_LEVEL MA_LOG_LEVEL_VERBOSE #ifdef WIN32 #ifndef __wtypes_h__ #include #endif #ifndef __WINDEF_ #include #endif #ifndef _WINUSER_ #include #endif #ifndef __RPC_H__ #include #endif #endif #include "sound.h" #define DR_FLAC_IMPLEMENTATION #include "extras/dr_flac.h" //flac #define DR_MP3_IMPLEMENTATION #include "extras/dr_mp3.h" //mp3 #define DR_WAV_IMPLEMENTATION #include "extras/dr_wav.h" //wav #include "extras/stb_vorbis.c" //vorbis #define MA_NO_WAV // disable wav encoding implementation #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" #include //std::max #include #include #include #include #include Sound* Sound::inst = nullptr; std::string Sound::FOLDER = "./"; Sound& Sound::instance() { if (!inst) { inst = new Sound(); } return *inst; } void Sound::deinitInstance() { if(inst) { inst->stopAll(); delete inst; inst = nullptr; } Log::info << "Sound deinited"; } void Sound::addPlayback(const std::string& name, float volume, uint64_t beginms, uint64_t length) { if(volume < 0.00001f) volume = 0.00001f; volume *= masterVolume; std::lock_guard lock(devicesMutex); for(SoundDevice* sd : devices) { sd->addPlayback(name, volume, beginms, length); } } void Sound::addPlayback(const std::string& audioDeviceName, const std::string& name, float volume, uint64_t beginms, uint64_t length, sndcb_func callback) { if(volume < 0.00001f) volume = 0.00001f; volume *= masterVolume; std::lock_guard lock(devicesMutex); for(SoundDevice* sd : devices) { if(sd->getName() == audioDeviceName) { sd->addPlayback(name, volume, beginms, length, callback); break; } } } bool Sound::addDefaultDevice() { SoundDevice* sd = SoundDevice::createDevice(&context); if(sd) { std::lock_guard lock(devicesMutex); devices.push_back(sd); } return sd; } bool Sound::addDeviceWithName(const std::string& name) { SoundDevice* sd = (name.empty() ? SoundDevice::createDevice(&context) : SoundDevice::createDevice(&context, name)); if(sd) { std::lock_guard lock(devicesMutex); devices.push_back(sd); } return sd; } void Sound::stopAll() { std::lock_guard lock(devicesMutex); for(SoundDevice* sd : devices) { sd->stop(); } } void Sound::reset() { Log::info << "ResetAudio"; deinit(); init(); masterVolume = 1.0; Log::info << "ResetAudio done"; } SampleReader* Sound::openFile(const std::string& name) { return SampleReader::createSampleReader(FOLDER + name); } std::vector Sound::getOutputs() { std::lock_guard lock(devicesMutex); std::vector out; out.reserve(devices.size()); for(SoundDevice* sd : devices) { out.push_back(sd->getName()); } return out; } void Sound::setMasterVolume(float m) { masterVolume = m; } float Sound::getMasterVolume() const { return masterVolume; } Sound::Sound() { init(); startBackgroundThread(); } Sound::~Sound() { deinit(); stopBackgroundThread(); } void Sound::deinit() { stopAll(); std::lock_guard lock(devicesMutex); for(SoundDevice* sd : devices) { delete sd; } devices.clear(); ma_context_uninit(&context); } void Sound::init() { if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) { Log::error << "Failed to initialize Sound context."; throw new std::exception(); } } void Sound::backgroundThreadLoop() { while(threadShouldrun) { std::this_thread::sleep_for(std::chrono::seconds(1)); cleanAllDecoders(); } } void Sound::cleanAllDecoders() { std::lock_guard lock(devicesMutex); for(SoundDevice* sd : devices) { sd->cleanupDecoders(); } } void Sound::startBackgroundThread() { threadShouldrun = true; backgroundCleanup = std::thread(&Sound::backgroundThreadLoop, this); } void Sound::stopBackgroundThread() { threadShouldrun = false; if(backgroundCleanup.joinable()) { backgroundCleanup.join(); } }