150 lines
3.6 KiB
C++
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;
|
|
}
|
|
|