dosgame1/audio/AudioPlayer.cpp

150 lines
3.6 KiB
C++

#include <go32.h>
#include "AudioPlayer.h"
#include "../system/Timer.h"
#include "../util/Asm.h"
#define DMA_BUFFER_SIZE (SB_BUFFER_SIZE * 4)
AudioPlayer audioPlayer;
void radPlayerWriteReg(void *p, uint16_t reg, uint8_t data) {
auto player = static_cast<AudioPlayer *>(p);
player->writeOpl(reg, data);
}
void audioPlayerOnTimer() {
audioPlayer.onTimer();
}
AudioPlayer::AudioPlayer() {
// Allocate twice the amount needed and select one half depending on whether it crosses a 64k boundary
_dmaBuffer.size = (DMA_BUFFER_SIZE + 15) >> (4-1);
_go32_dpmi_allocate_dos_memory(&_dmaBuffer);
auto physFirst = (_dmaBuffer.rm_segment << 4) + _dmaBuffer.rm_offset;
auto physSecond = physFirst + DMA_BUFFER_SIZE;
auto pageFirst = physFirst >> 16;
auto pageSecond = physSecond >> 16;
if (pageFirst == pageSecond) {
// Use first half
_buffers = reinterpret_cast<decltype(_buffers)>(physFirst);
_dmaPage = pageFirst;
_dmaOffset = physFirst & 0xFFFF;
} else {
// Use second half
_buffers = reinterpret_cast<decltype(_buffers)>(physSecond);
_dmaPage = pageSecond;
_dmaOffset = physSecond & 0xFFFF;
}
timer.setCallback(audioPlayerOnTimer);
}
AudioPlayer::~AudioPlayer() {
timer.setCallback(nullptr);
_go32_dpmi_free_dos_memory(&_dmaBuffer);
}
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.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, int priority, int flags) {
if (priority > AUDIO_MAX_PRIORITY) priority = AUDIO_MAX_PRIORITY;
}
bool AudioPlayer::isPlaying(const Audio &audio) {
for (auto &channel : _channels) {
if (channel.audio == &audio) return true;
}
return false;
}
void AudioPlayer::stopAudio(Audio &audio) {
for (auto &channel : _channels) {
if (channel.audio == &audio) {
channel.audio = nullptr;
channel.loop = false;
}
}
}
void AudioPlayer::stopAllAudio() {
for (auto &channel : _channels) {
channel.audio = nullptr;
channel.loop = false;
}
}
bool AudioPlayer::isPlaying(const Music &music) const {
return _currentMusic == &music;
}
void AudioPlayer::writeOpl(uint16_t reg, uint8_t data) const {
if (reg >= 0x100) {
outb(_oplReg + 2, reg & 0xff);
outb(_oplReg + 3, data);
} else {
outb(_oplReg, reg);
outb(_oplReg + 1, data);
}
}
void AudioPlayer::onTimer() {
if (_paused) return;
if (!_currentMusic) return;
_musicPlayer.Update();
}
void AudioPlayer::generateSamples() {
}
void AudioPlayer::copySamples() {
// No data available - should not happen, but let's force generate a block
if (_nextBufferReadIndex == _nextBufferWriteIndex) {
generateSamples();
}
dosmemput(_buffers, SB_BUFFER_SIZE, (_dmaBuffer.rm_segment << 4) + _nextBufferReadIndex * SB_BUFFER_SIZE);
_nextBufferReadIndex = (_nextBufferReadIndex + 1) & 3;
}