soundboard/src/sound.cpp

207 lines
4.1 KiB
C++

// 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 <wtypes.h>
#endif
#ifndef __WINDEF_
#include <windef.h>
#endif
#ifndef _WINUSER_
#include <winuser.h>
#endif
#ifndef __RPC_H__
#include <rpc.h>
#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 <algorithm> //std::max
#include <cstring>
#include <cassert>
#include <cmath>
#include <iostream>
#include <Log.h>
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(devicesMutex);
devices.push_back(sd);
}
return sd;
}
void Sound::stopAll() {
std::lock_guard<std::mutex> 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<std::string> Sound::getOutputs() {
std::lock_guard<std::mutex> lock(devicesMutex);
std::vector<std::string> 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<std::mutex> 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<std::mutex> 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();
}
}