#include "AudioPlayer.h" #include "../system/Opl.h" #include "../system/Timer.h" #include "../util/Log.h" AudioPlayer audioPlayer; void radPlayerWriteReg(void *p, uint16_t reg, uint8_t data) { auto player = static_cast(p); player->writeOpl(reg, data); } void audioPlayerOnTimer() { audioPlayer.onTimer(); } void audioPlayerOnTimerDelayed() { static int idle = 10; if (--idle) return; Timer::instance().setCallback(audioPlayerOnTimer); } AudioPlayer::AudioPlayer() { Timer::instance().setCallback(audioPlayerOnTimerDelayed); } AudioPlayer::~AudioPlayer() { Timer::instance().setCallback(nullptr); } void AudioPlayer::playMusic(Music &music) { stopMusic(); _currentMusic = &music; _musicPlayer.Init(_currentMusic->getData(), radPlayerWriteReg, this); auto hz = _musicPlayer.GetHertz(); if (hz < 0) { stopMusic(); return; } // Start music playback Timer::instance().setFrequency(hz); resumeMusic(); } void AudioPlayer::stopMusic() { if (!_currentMusic) return; _musicPlayer.Stop(); _paused = true; _currentMusic = nullptr; } void AudioPlayer::pauseMusic() { _paused = true; } void AudioPlayer::resumeMusic() { if (!_currentMusic) return; _paused = false; } void AudioPlayer::playAudio(Audio &audio, unsigned priority, int flags) { if (priority > AUDIO_MAX_PRIORITY) priority = AUDIO_MAX_PRIORITY; _channelMutex.lock(); if (flags & AUDIO_PLAY_FIXED_PRIORITY) { if (_channels[priority].audio) { _channels[priority].audio = 0; } _channels[priority].audio = &audio; _channels[priority].loop = flags & AUDIO_PLAY_LOOP; _channels[priority].pos = 0; } else { size_t shortestPriority = 0; size_t remainingShortest = -1; for (auto i = 0; i < priority; i++) { if (!_channels[i].audio) { _channels[i].audio = &audio; _channels[i].loop = flags & AUDIO_PLAY_LOOP; _channels[i].pos = 0; _channelMutex.unlock(); return; } if (!_channels[i].loop) { auto remaining = _channels[i].audio->_length - _channels[i].pos; if (remaining < remainingShortest) { shortestPriority = i; remainingShortest = remaining; } } } if (_channels[shortestPriority].audio) { _channels[shortestPriority].audio = 0; } _channels[shortestPriority].audio = &audio; _channels[shortestPriority].loop = flags & AUDIO_PLAY_LOOP; _channels[shortestPriority].pos = 0; } _channelMutex.unlock(); } bool AudioPlayer::isPlaying(const Audio &audio) { for (auto &channel : _channels) { if (channel.audio == &audio) return true; } return false; } void AudioPlayer::stopAudio(Audio &audio) { _channelMutex.lock(); for (auto &channel : _channels) { if (channel.audio == &audio) { channel.audio = nullptr; channel.loop = false; } } _channelMutex.unlock(); } void AudioPlayer::stopAllAudio() { _channelMutex.lock(); for (auto &channel : _channels) { channel.audio = nullptr; channel.loop = false; } _channelMutex.unlock(); } void AudioPlayer::generateSamples(int8_t *buffer, size_t size) { _channelMutex.lock(); for (size_t i = 0; i < size; i++) { int16_t accum = 0; for (auto &channel : _channels) { if (channel.audio) { auto sample = channel.audio->_data[channel.pos++]; if (channel.pos >= channel.audio->_length) { if (channel.loop) { channel.pos = 0; } else { channel.audio = nullptr; } } accum += sample; } } buffer[i] = (accum < 0) ? -((-accum) >> 3) : (accum >> 3); } _channelMutex.unlock(); } bool AudioPlayer::isPlaying(const Music &music) const { return _currentMusic == &music; } void AudioPlayer::writeOpl(uint16_t reg, uint8_t data) const { Opl::write(reg, data); } void AudioPlayer::onTimer() { if (_paused) return; if (!_currentMusic) return; _musicPlayer.Update(); }