2021-12-13 00:28:04 +01:00
|
|
|
// Diese Datei ist stark an den examples von miniaudio orientiert (vor allem simple_mixing.c). Die Struktur ähnelt sich daher möglicherweise.
|
|
|
|
|
|
|
|
|
2021-12-13 14:48:43 +01:00
|
|
|
//#define MA_DEBUG_OUTPUT
|
2021-12-13 00:28:04 +01:00
|
|
|
//#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
|
|
|
|
|
2022-04-02 23:42:56 +02:00
|
|
|
#define MA_NO_WAV // disable wav encoding implementation
|
2021-12-13 00:28:04 +01:00
|
|
|
#define MINIAUDIO_IMPLEMENTATION
|
|
|
|
#include "miniaudio.h"
|
|
|
|
|
|
|
|
#include <algorithm> //std::max
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cmath>
|
|
|
|
#include <iostream>
|
|
|
|
|
2021-12-13 14:48:43 +01:00
|
|
|
#include <Log.h>
|
2021-12-13 00:28:04 +01:00
|
|
|
|
|
|
|
Sound* Sound::inst = nullptr;
|
2021-12-13 17:28:32 +01:00
|
|
|
std::string Sound::FOLDER = "./";
|
2021-12-13 00:28:04 +01:00
|
|
|
|
|
|
|
Sound& Sound::instance() {
|
|
|
|
if (!inst) {
|
2021-12-13 01:23:03 +01:00
|
|
|
inst = new Sound();
|
2021-12-13 00:28:04 +01:00
|
|
|
}
|
|
|
|
return *inst;
|
|
|
|
}
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
void Sound::deinitInstance() {
|
2021-12-13 00:28:04 +01:00
|
|
|
if(inst) {
|
|
|
|
inst->stopAll();
|
|
|
|
delete inst;
|
|
|
|
inst = nullptr;
|
|
|
|
}
|
|
|
|
|
2021-12-13 14:48:43 +01:00
|
|
|
Log::info << "Sound deinited";
|
2021-12-13 00:28:04 +01:00
|
|
|
}
|
|
|
|
|
2021-12-22 12:52:25 +01:00
|
|
|
void Sound::addPlayback(const std::string& name, float volume, uint64_t beginms, uint64_t length) {
|
2021-12-13 17:28:32 +01:00
|
|
|
if(volume < 0.00001f)
|
|
|
|
volume = 0.00001f;
|
|
|
|
|
2022-04-02 23:42:56 +02:00
|
|
|
volume *= masterVolume;
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
2021-12-13 00:28:04 +01:00
|
|
|
for(SoundDevice* sd : devices) {
|
2021-12-22 12:52:25 +01:00
|
|
|
sd->addPlayback(name, volume, beginms, length);
|
2021-12-13 00:28:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-22 12:52:25 +01:00
|
|
|
void Sound::addPlayback(const std::string& audioDeviceName, const std::string& name, float volume, uint64_t beginms, uint64_t length, sndcb_func callback) {
|
2021-12-20 01:30:04 +01:00
|
|
|
if(volume < 0.00001f)
|
|
|
|
volume = 0.00001f;
|
|
|
|
|
2022-04-02 23:42:56 +02:00
|
|
|
volume *= masterVolume;
|
|
|
|
|
2021-12-20 01:30:04 +01:00
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
|
|
|
for(SoundDevice* sd : devices) {
|
|
|
|
if(sd->getName() == audioDeviceName) {
|
2021-12-22 12:52:25 +01:00
|
|
|
sd->addPlayback(name, volume, beginms, length, callback);
|
2021-12-20 01:30:04 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-13 00:28:04 +01:00
|
|
|
bool Sound::addDefaultDevice() {
|
|
|
|
SoundDevice* sd = SoundDevice::createDevice(&context);
|
|
|
|
if(sd) {
|
2021-12-18 15:34:27 +01:00
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
2021-12-13 00:28:04 +01:00
|
|
|
devices.push_back(sd);
|
|
|
|
}
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sound::addDeviceWithName(const std::string& name) {
|
2021-12-13 14:48:43 +01:00
|
|
|
SoundDevice* sd = (name.empty() ? SoundDevice::createDevice(&context) : SoundDevice::createDevice(&context, name));
|
2021-12-13 00:28:04 +01:00
|
|
|
if(sd) {
|
2021-12-18 15:34:27 +01:00
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
2021-12-13 00:28:04 +01:00
|
|
|
devices.push_back(sd);
|
|
|
|
}
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sound::stopAll() {
|
2021-12-18 15:34:27 +01:00
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
|
|
|
|
2021-12-13 00:28:04 +01:00
|
|
|
for(SoundDevice* sd : devices) {
|
|
|
|
sd->stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-13 14:48:43 +01:00
|
|
|
void Sound::reset() {
|
|
|
|
Log::info << "ResetAudio";
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
deinit();
|
|
|
|
init();
|
|
|
|
|
2022-04-02 23:42:56 +02:00
|
|
|
masterVolume = 1.0;
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
Log::info << "ResetAudio done";
|
|
|
|
}
|
|
|
|
|
2021-12-20 00:19:35 +01:00
|
|
|
SampleReader* Sound::openFile(const std::string& name) {
|
|
|
|
return SampleReader::createSampleReader(FOLDER + name);
|
|
|
|
}
|
|
|
|
|
2021-12-20 01:30:04 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-04-02 23:42:56 +02:00
|
|
|
void Sound::setMasterVolume(float m) {
|
|
|
|
masterVolume = m;
|
|
|
|
}
|
|
|
|
float Sound::getMasterVolume() const {
|
|
|
|
return masterVolume;
|
|
|
|
}
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
Sound::Sound() {
|
|
|
|
init();
|
|
|
|
startBackgroundThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
Sound::~Sound() {
|
|
|
|
deinit();
|
|
|
|
stopBackgroundThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sound::deinit() {
|
2021-12-13 14:48:43 +01:00
|
|
|
stopAll();
|
2021-12-18 15:34:27 +01:00
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
2021-12-13 14:48:43 +01:00
|
|
|
for(SoundDevice* sd : devices) {
|
|
|
|
delete sd;
|
|
|
|
}
|
|
|
|
devices.clear();
|
2021-12-18 15:34:27 +01:00
|
|
|
|
2021-12-13 14:48:43 +01:00
|
|
|
ma_context_uninit(&context);
|
2021-12-18 15:34:27 +01:00
|
|
|
}
|
2021-12-13 14:48:43 +01:00
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
void Sound::init() {
|
2021-12-13 14:48:43 +01:00
|
|
|
if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
|
|
|
|
Log::error << "Failed to initialize Sound context.";
|
|
|
|
throw new std::exception();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
void Sound::backgroundThreadLoop() {
|
|
|
|
while(threadShouldrun) {
|
2021-12-18 23:53:02 +01:00
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
2021-12-18 15:34:27 +01:00
|
|
|
cleanAllDecoders();
|
2021-12-13 01:23:03 +01:00
|
|
|
}
|
2021-12-13 00:28:04 +01:00
|
|
|
}
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
void Sound::cleanAllDecoders() {
|
|
|
|
std::lock_guard<std::mutex> lock(devicesMutex);
|
|
|
|
|
2021-12-13 00:28:04 +01:00
|
|
|
for(SoundDevice* sd : devices) {
|
2021-12-18 15:34:27 +01:00
|
|
|
sd->cleanupDecoders();
|
2021-12-13 00:28:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-18 15:34:27 +01:00
|
|
|
void Sound::startBackgroundThread() {
|
|
|
|
threadShouldrun = true;
|
|
|
|
backgroundCleanup = std::thread(&Sound::backgroundThreadLoop, this);
|
2021-12-18 15:19:14 +01:00
|
|
|
}
|
2021-12-18 15:34:27 +01:00
|
|
|
|
|
|
|
void Sound::stopBackgroundThread() {
|
|
|
|
threadShouldrun = false;
|
|
|
|
if(backgroundCleanup.joinable()) {
|
|
|
|
backgroundCleanup.join();
|
|
|
|
}
|
|
|
|
}
|