our_dick/include/audio/impl/channel.hpp

116 lines
2.7 KiB
C++

/**
This file is a part of our_dick
Copyright (C) 2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_AUDIO_CHANNEL_IMPL_HPP
#define OUR_DICK_AUDIO_CHANNEL_IMPL_HPP
#include <atomic>
#include <cstdlib> //size_t
#include <rexy/mpmc_queue.hpp>
#include "audio/mixdata.hpp"
namespace sfx::impl{
class channel
{
public:
static constexpr size_t chunk_size = 256;
using chunk = mixrawdata<chunk_size>;
private:
rexy::mpmc_queue<mixrawdata<chunk_size>> m_data;
std::atomic_bool m_paused;
std::atomic_bool m_active;
bool m_stopped;
//audio thread access only!
struct alignas(64){
chunk data = {};
size_t offset = 0;
}m_playing_chunk;
public:
channel(void);
explicit channel(size_t maxsize);
channel(const channel& c);
channel(channel&& c);
~channel(void) = default;
channel& operator=(const channel& c);
channel& operator=(channel&& c);
chunk pop(void);
bool try_pop(chunk& m);
void resize_buffer(size_t newsize);
template<size_t Size>
void play(const mixrawdata<Size>& m);
template<size_t Size>
bool try_play(const mixrawdata<Size>& m);
void pause(void);
void resume(void);
void stop(void);
bool is_paused(void)const;
bool is_playing(void)const;
bool is_stopped(void)const;
chunk& playing_chunk(void);
const chunk& playing_chunk(void)const;
size_t& playing_offset(void);
const size_t& playing_offset(void)const;
bool is_active(void)const;
void set_active(bool b);
private:
void wait_for_consumer(void);
};
template<size_t Size>
void channel::play(const mixrawdata<Size>& m){
if constexpr(Size > chunk_size){
size_t chunk_frames = chunk_size / m.channels;
for(size_t i = 0;i < m.frames;i += chunk_frames){
m_data.emplace(m, i);
}
}else{
m_data.emplace(m);
}
}
template<size_t Size>
bool channel::try_play(const mixrawdata<Size>& m){
if constexpr(Size > chunk_size){
size_t chunk_frames = chunk_size / m.channels;
for(size_t i = 0;i < m.frames;i += chunk_frames){
if(!m_data.try_emplace(m, i))
return false;
}
return true;
}else{
return m_data.try_emplace(m);
}
}
}
#endif