Mesen/Core/HdAudioDevice.cpp

172 lines
4.6 KiB
C++

#include "stdafx.h"
#include "HdAudioDevice.h"
#include "HdData.h"
#include "Console.h"
HdAudioDevice::HdAudioDevice(shared_ptr<Console> console, HdPackData* hdData)
{
_hdData = hdData;
_album = 0;
_playbackOptions = 0;
_trackError = false;
_sfxVolume = 128;
_bgmVolume = 128;
_oggMixer = console->GetSoundMixer()->GetOggMixer();
_oggMixer->SetBgmVolume(_bgmVolume);
_oggMixer->SetSfxVolume(_sfxVolume);
}
void HdAudioDevice::StreamState(bool saving)
{
int32_t trackOffset = 0;
if(saving) {
trackOffset = _oggMixer->GetBgmOffset();
if(trackOffset < 0) {
_lastBgmTrack = -1;
}
Stream(_album, _lastBgmTrack, trackOffset, _sfxVolume, _bgmVolume, _playbackOptions);
} else {
Stream(_album, _lastBgmTrack, trackOffset, _sfxVolume, _bgmVolume, _playbackOptions);
if(_lastBgmTrack != -1 && trackOffset > 0) {
PlayBgmTrack(_lastBgmTrack, trackOffset);
}
_oggMixer->SetBgmVolume(_bgmVolume);
_oggMixer->SetSfxVolume(_sfxVolume);
_oggMixer->SetPlaybackOptions(_playbackOptions);
}
}
bool HdAudioDevice::PlayBgmTrack(uint8_t track, uint32_t startOffset)
{
int trackId = _album * 256 + track;
auto result = _hdData->BgmFilesById.find(trackId);
if(result != _hdData->BgmFilesById.end()) {
if(_oggMixer->Play(result->second, false, startOffset)) {
_lastBgmTrack = trackId;
return true;
}
} else {
MessageManager::Log("[HDPack] Invalid album+track combination: " + std::to_string(_album) + ":" + std::to_string(track));
}
return false;
}
bool HdAudioDevice::PlaySfx(uint8_t sfxNumber)
{
auto result = _hdData->SfxFilesById.find(_album * 256 + sfxNumber);
if(result != _hdData->SfxFilesById.end()) {
return !_oggMixer->Play(result->second, true, 0);
} else {
MessageManager::Log("[HDPack] Invalid album+sfx number combination: " + std::to_string(_album) + ":" + std::to_string(sfxNumber));
return false;
}
}
void HdAudioDevice::ProcessControlFlags(uint8_t flags)
{
_oggMixer->SetPausedFlag((flags & 0x01) == 0x01);
if(flags & 0x02) {
_oggMixer->StopBgm();
}
if(flags & 0x04) {
_oggMixer->StopSfx();
}
}
void HdAudioDevice::GetMemoryRanges(MemoryRanges & ranges)
{
bool useAlternateRegisters = (_hdData->OptionFlags & (int)HdPackOptions::AlternateRegisterRange) == (int)HdPackOptions::AlternateRegisterRange;
ranges.SetAllowOverride();
if(useAlternateRegisters) {
for(int i = 0; i < 7; i++) {
ranges.AddHandler(MemoryOperation::Write, 0x3002 + i * 0x10);
}
ranges.AddHandler(MemoryOperation::Read, 0x4018);
ranges.AddHandler(MemoryOperation::Read, 0x4019);
} else {
ranges.AddHandler(MemoryOperation::Any, 0x4100, 0x4106);
}
}
void HdAudioDevice::WriteRAM(uint16_t addr, uint8_t value)
{
//$4100/$3002: Playback Options
//$4101/$3012: Playback Control
//$4102/$3022: BGM Volume
//$4103/$3032: SFX Volume
//$4104/$3042: Album Number
//$4105/$3052: Play BGM Track
//$4106/$3062: Play SFX Track
int regNumber = addr > 0x4100 ? (addr & 0xF) : ((addr & 0xF0) >> 4);
switch(regNumber) {
//Playback Options
//Bit 0: Loop BGM
//Bit 1-7: Unused, reserved - must be 0
case 0:
_playbackOptions = value;
_oggMixer->SetPlaybackOptions(_playbackOptions);
break;
//Playback Control
//Bit 0: Toggle Pause/Resume (only affects BGM)
//Bit 1: Stop BGM
//Bit 2: Stop all SFX
//Bit 3-7: Unused, reserved - must be 0
case 1: ProcessControlFlags(value); break;
//BGM Volume: 0 = mute, 255 = max
//Also has an immediate effect on currently playing BGM
case 2:
_bgmVolume = value;
_oggMixer->SetBgmVolume(value);
break;
//SFX Volume: 0 = mute, 255 = max
//Also has an immediate effect on all currently playing SFX
case 3:
_sfxVolume = value;
_oggMixer->SetSfxVolume(value);
break;
//Album number: 0-255 (Allows for up to 64k BGM and SFX tracks)
//No immediate effect - only affects subsequent $4FFE/$4FFF writes
case 4: _album = value; break;
//Play BGM track (0-255 = track number)
//Stop the current BGM and starts a new track
case 5: _trackError = PlayBgmTrack(value, 0); break;
//Play sound effect (0-255 = sfx number)
//Plays a new sound effect (no limit to the number of simultaneous sound effects)
case 6: _trackError = PlaySfx(value); break;
}
}
uint8_t HdAudioDevice::ReadRAM(uint16_t addr)
{
//$4100/$4018: Status
//$4101/$4019: Revision
//$4102: 'N' (signature to help detection)
//$4103: 'E'
//$4103: 'A'
switch(addr & 0x7) {
case 0:
//Status
return (
(_oggMixer->IsBgmPlaying() ? 1 : 0) |
(_oggMixer->IsSfxPlaying() ? 2 : 0) |
(_trackError ? 4 : 0)
);
case 1: return 1; //Revision
case 2: return 'N'; //NES
case 3: return 'E'; //Enhanced
case 4: return 'A'; //Audio
}
return 0;
}