This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/audaspace/src/fx/DynamicMusic.cpp
Sergey Sharybin e5a74f3ad3 Audaspace: Fix -Wreorder warning
Makes building less noisy, helps catching real introduced warnings/errors.

@xeXyon, mind having a look here and possibly apply to upstream? :)
2017-11-28 14:24:56 +01:00

347 lines
8.3 KiB
C++

/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/DynamicMusic.h"
#include "generator/Silence.h"
#include "fx/Fader.h"
#include "fx/Limiter.h"
#include <mutex>
#include <condition_variable>
AUD_NAMESPACE_BEGIN
DynamicMusic::DynamicMusic(std::shared_ptr<IDevice> device) :
m_fadeTime(1.0f), m_device(device)
{
m_id = 0;
m_transitioning = false;
m_stopThread = false;
m_volume = m_device->getVolume();
m_scenes.push_back(std::vector<std::shared_ptr<ISound>>(1, nullptr));
}
DynamicMusic::~DynamicMusic()
{
stop();
}
int DynamicMusic::addScene(std::shared_ptr<ISound> sound)
{
std::vector<std::shared_ptr<ISound>> v;
m_scenes.push_back(v);
for(int i = 0; i < m_scenes.size()-1; i++)
m_scenes.back().push_back(nullptr);
for(int i = 0; i < m_scenes.size()-1; i++)
m_scenes[i].push_back(nullptr);
m_scenes.back().push_back(sound);
return m_scenes.size() - 1;
}
bool DynamicMusic::changeScene(int id)
{
if(id >= m_scenes.size() || m_transitioning)
return false;
else
{
if(m_fadeThread.joinable())
m_fadeThread.join();
m_device->lock();
if(id == m_id)
{
m_currentHandle->setVolume(m_volume);
m_currentHandle->setLoopCount(-1);
}
else
{
m_soundTarget = id;
if(m_scenes[m_id][id] == nullptr)
{
m_stopThread = false;
if((m_scenes[m_id][m_id] != nullptr && m_currentHandle->getStatus() != STATUS_INVALID) || m_scenes[m_soundTarget][m_soundTarget] != nullptr)
{
m_transitioning = true;
if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
{
m_device->lock();
m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
m_currentHandle->setVolume(0.0f);
m_currentHandle->setLoopCount(-1);
m_device->unlock();
m_fadeThread = std::thread(&DynamicMusic::fadeInThread, this);
}
else
{
if(m_scenes[m_soundTarget][m_soundTarget] != nullptr)
{
m_device->lock();
m_transitionHandle = m_currentHandle;
m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
m_currentHandle->setVolume(0.0f);
m_currentHandle->setLoopCount(-1);
m_device->unlock();
m_fadeThread = std::thread(&DynamicMusic::crossfadeThread, this);
}
else
{
m_transitionHandle = m_currentHandle;
m_currentHandle = nullptr;
m_fadeThread = std::thread(&DynamicMusic::fadeOutThread, this);
}
}
}
}
else
{
if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
transitionCallback(this);
else
{
m_currentHandle->setLoopCount(0);
m_currentHandle->setStopCallback(transitionCallback, this);
}
}
}
m_device->unlock();
return true;
}
}
int DynamicMusic::getScene()
{
return m_id;
}
bool DynamicMusic::addTransition(int init, int end, std::shared_ptr<ISound> sound)
{
if(init != end && init < m_scenes.size() && end < m_scenes.size() && init >= 0 && end >= 0)
{
m_scenes[init][end] = sound;
return true;
}
return false;
}
void DynamicMusic::setFadeTime(float seconds)
{
m_device->lock();
m_fadeTime = seconds;
m_device->unlock();
}
float DynamicMusic::getFadeTime()
{
return m_fadeTime;
}
bool DynamicMusic::resume()
{
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->resume();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->resume();
return result || resultTrans;
}
bool DynamicMusic::pause()
{
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->pause();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->pause();
return result || resultTrans;
}
bool DynamicMusic::seek(float position)
{
bool result;
if(m_currentHandle != nullptr)
{
result = m_currentHandle->seek(position);
if(m_transitionHandle != nullptr && result == true)
m_transitionHandle->stop();
}
return result;
}
float DynamicMusic::getPosition()
{
float result = 0.0f;
if(m_currentHandle != nullptr)
result = m_currentHandle->getPosition();
return result;
}
float DynamicMusic::getVolume()
{
return m_volume;
}
bool DynamicMusic::setVolume(float volume)
{
m_volume = volume;
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->setVolume(volume);
if(m_transitionHandle != nullptr)
{
m_device->lock();
if(volume<m_transitionHandle->getVolume())
resultTrans = m_transitionHandle->setVolume(0.0f);
m_device->unlock();
}
if(m_currentHandle == nullptr && m_transitionHandle == nullptr)
result = true;
return result || resultTrans;
}
Status DynamicMusic::getStatus()
{
if(m_currentHandle != nullptr)
{
Status result = m_currentHandle->getStatus();
return result;
}
else
return STATUS_INVALID;
}
bool DynamicMusic::stop()
{
m_stopThread = true;
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->stop();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->stop();
if(m_fadeThread.joinable())
m_fadeThread.join();
m_id = 0;
return result || resultTrans;
}
void DynamicMusic::transitionCallback(void* player)
{
auto dat = reinterpret_cast<DynamicMusic*>(player);
dat->m_transitioning = true;
dat->m_device->lock();
dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_id][dat->m_soundTarget]);
dat->m_currentHandle->setVolume(dat->m_volume);
if(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget] != nullptr)
dat->m_currentHandle->setStopCallback(sceneCallback, player);
dat->m_device->unlock();
}
void DynamicMusic::sceneCallback(void* player)
{
auto dat = reinterpret_cast<DynamicMusic*>(player);
dat->m_device->lock();
dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget]);
dat->m_currentHandle->setVolume(dat->m_volume);
dat->m_currentHandle->setLoopCount(-1);
dat->m_device->unlock();
dat->m_id = int(dat->m_soundTarget);
dat->m_soundTarget = -1;
dat->m_transitioning = false;
}
void DynamicMusic::crossfadeThread()
{
float currentVol = m_transitionHandle->getVolume();
float nextVol = m_currentHandle->getVolume();
float increment;
while(nextVol < m_volume && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
currentVol -= increment;
nextVol += increment;
if(currentVol < 0)
currentVol = 0;
if(nextVol > m_volume)
nextVol = m_volume;
m_transitionHandle->setVolume(currentVol);
m_currentHandle->setVolume(nextVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
if(m_stopThread)
m_transitionHandle->setVolume(m_volume);
m_transitionHandle->stop();
m_id = int(m_soundTarget);
m_transitioning = false;
}
void DynamicMusic::fadeInThread()
{
float nextVol = m_currentHandle->getVolume();
float increment;
while(nextVol < m_volume && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
nextVol += increment;
if(nextVol > m_volume)
nextVol = m_volume;
m_currentHandle->setVolume(nextVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
if(m_stopThread)
m_currentHandle->setVolume(m_volume);
m_id = int(m_soundTarget);
m_transitioning = false;
}
void DynamicMusic::fadeOutThread()
{
float currentVol = m_transitionHandle->getVolume();
float increment;
while(currentVol > 0.0f && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
currentVol -= increment;
if(currentVol < 0)
currentVol = 0;
m_transitionHandle->setVolume(currentVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
m_transitionHandle->stop();
m_id = int(m_soundTarget);
m_transitioning = false;
}
AUD_NAMESPACE_END