BACKENDS: ATARI: DMA playback is not always active

E.g. in the overlay there's no need to steal cycles for playing empty
sample buffer.

Also make STMIDI default audio driver for the slim version.
This commit is contained in:
Miro Kropacek 2023-06-11 18:06:27 +02:00
parent 5537759c53
commit 2ce02658ec
6 changed files with 215 additions and 198 deletions

View File

@ -32,14 +32,10 @@
#define DEFAULT_OUTPUT_RATE 24585
static bool s_audioNotAvailable = true;
void AtariAudioShutdown() {
if (!s_audioNotAvailable) {
Buffoper(0x00);
Sndstatus(SND_RESET);
Unlocksnd();
}
Buffoper(0x00);
Sndstatus(SND_RESET);
Unlocksnd();
}
AtariMixerManager::AtariMixerManager() : MixerManager() {
@ -61,9 +57,6 @@ AtariMixerManager::~AtariMixerManager() {
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
if (s_audioNotAvailable)
return;
AtariAudioShutdown();
Mfree(_atariSampleBuffer);
@ -74,135 +67,121 @@ AtariMixerManager::~AtariMixerManager() {
void AtariMixerManager::init() {
long cookie;
bool useDevconnectReturnValue = false;
bool useDevconnectReturnValue = Getcookie(C__SND, &cookie) == C_FOUND && (cookie & SND_EXT) != 0;
if (Getcookie(C__SND, &cookie) == C_FOUND) {
if (cookie & SND_16BIT)
s_audioNotAvailable = false;
int clk;
useDevconnectReturnValue = (cookie & SND_EXT) != 0;
if (Locksnd() < 0)
error("Sound system is locked");
// try XBIOS APIs which do not set SND_EXT in _SND
useDevconnectReturnValue |= (Getcookie(C_STFA, &cookie) == C_FOUND); // STFA
useDevconnectReturnValue |= (Getcookie(C_McSn, &cookie) == C_FOUND); // X-SOUND, MacSound
// reset connection matrix (and other settings)
Sndstatus(SND_RESET);
int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8, diff6;
diff50 = abs(49170 - (int)_outputRate);
diff33 = abs(32780 - (int)_outputRate);
diff25 = abs(24585 - (int)_outputRate);
diff20 = abs(19668 - (int)_outputRate);
diff16 = abs(16390 - (int)_outputRate);
diff12 = abs(12292 - (int)_outputRate);
diff10 = abs(9834 - (int)_outputRate);
diff8 = abs(8195 - (int)_outputRate);
if (diff50 < diff33) {
_outputRate = 49170;
clk = CLK50K;
} else if (diff33 < diff25) {
_outputRate = 32780;
clk = CLK33K;
} else if (diff25 < diff20) {
_outputRate = 24585;
clk = CLK25K;
} else if (diff20 < diff16) {
_outputRate = 19668;
clk = CLK20K;
} else if (diff16 < diff12) {
_outputRate = 16390;
clk = CLK16K;
} else if (diff12 < diff10) {
_outputRate = 12292;
clk = CLK12K;
} else if (diff10 < diff8) {
_outputRate = 9834;
clk = CLK10K;
} else {
_outputRate = 8195;
clk = CLK8K;
}
if (s_audioNotAvailable) {
warning("Mixer manager requires 16-bit stereo mode, disabling");
} else {
int clk;
// first try to use Devconnect() with a Falcon prescaler
if (Devconnect(DMAPLAY, DAC, CLK25M, clk, NO_SHAKE) != 0) {
// the return value is broken on Falcon
if (useDevconnectReturnValue) {
if (Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, NO_SHAKE) == 0) {
// calculate compatible prescaler
diff50 = abs(50066 - (int)_outputRate);
diff25 = abs(25033 - (int)_outputRate);
diff12 = abs(12517 - (int)_outputRate);
diff6 = abs(6258 - (int)_outputRate);
if (Locksnd() < 0)
error("Sound system is locked");
// try XBIOS APIs which do not set SND_EXT in _SND
useDevconnectReturnValue |= (Getcookie(C_STFA, &cookie) == C_FOUND); // STFA
useDevconnectReturnValue |= (Getcookie(C_McSn, &cookie) == C_FOUND); // X-SOUND, MacSound
// reset connection matrix (and other settings)
Sndstatus(SND_RESET);
int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8, diff6;
diff50 = abs(49170 - (int)_outputRate);
diff33 = abs(32780 - (int)_outputRate);
diff25 = abs(24585 - (int)_outputRate);
diff20 = abs(19668 - (int)_outputRate);
diff16 = abs(16390 - (int)_outputRate);
diff12 = abs(12292 - (int)_outputRate);
diff10 = abs(9834 - (int)_outputRate);
diff8 = abs(8195 - (int)_outputRate);
if (diff50 < diff33) {
_outputRate = 49170;
clk = CLK50K;
} else if (diff33 < diff25) {
_outputRate = 32780;
clk = CLK33K;
} else if (diff25 < diff20) {
_outputRate = 24585;
clk = CLK25K;
} else if (diff20 < diff16) {
_outputRate = 19668;
clk = CLK20K;
} else if (diff16 < diff12) {
_outputRate = 16390;
clk = CLK16K;
} else if (diff12 < diff10) {
_outputRate = 12292;
clk = CLK12K;
} else if (diff10 < diff8) {
_outputRate = 9834;
clk = CLK10K;
} else {
_outputRate = 8195;
clk = CLK8K;
}
// first try to use Devconnect() with a Falcon prescaler
if (Devconnect(DMAPLAY, DAC, CLK25M, clk, NO_SHAKE) != 0) {
// the return value is broken on Falcon
if (useDevconnectReturnValue) {
if (Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, NO_SHAKE) == 0) {
// calculate compatible prescaler
diff50 = abs(50066 - (int)_outputRate);
diff25 = abs(25033 - (int)_outputRate);
diff12 = abs(12517 - (int)_outputRate);
diff6 = abs(6258 - (int)_outputRate);
if (diff50 < diff25) {
_outputRate = 50066;
clk = PRE160;
} else if (diff25 < diff12) {
_outputRate = 25033;
clk = PRE320;
} else if (diff12 < diff6) {
_outputRate = 12517;
clk = PRE640;
} else {
_outputRate = 6258;
clk = PRE1280;
}
Soundcmd(SETPRESCALE, clk);
if (diff50 < diff25) {
_outputRate = 50066;
clk = PRE160;
} else if (diff25 < diff12) {
_outputRate = 25033;
clk = PRE320;
} else if (diff12 < diff6) {
_outputRate = 12517;
clk = PRE640;
} else {
error("Devconnect() failed");
_outputRate = 6258;
clk = PRE1280;
}
Soundcmd(SETPRESCALE, clk);
} else {
error("Devconnect() failed");
}
}
ConfMan.setInt("output_rate", _outputRate);
debug("setting %d Hz mixing frequency", _outputRate);
_samples = 8192;
while (_samples * 16 > _outputRate * 2)
_samples >>= 1;
ConfMan.registerDefault("audio_buffer_size", (int)_samples);
int samples = ConfMan.getInt("audio_buffer_size");
if (samples > 0)
_samples = samples;
ConfMan.setInt("audio_buffer_size", (int)_samples);
debug("sample buffer size: %d", _samples);
ConfMan.flushToDisk();
_atariSampleBufferSize = _samples * 4;
_atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
if (!_atariSampleBuffer)
error("Failed to allocate memory in ST RAM");
_atariPhysicalSampleBuffer = _atariSampleBuffer;
_atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
Setmode(MODE_STEREO16);
Soundcmd(ADDERIN, MATIN);
Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
_samplesBuf = new uint8[_samples * 4];
}
ConfMan.setInt("output_rate", _outputRate);
debug("setting %d Hz mixing frequency", _outputRate);
_samples = 8192;
while (_samples * 16 > _outputRate * 2)
_samples >>= 1;
ConfMan.registerDefault("audio_buffer_size", (int)_samples);
int samples = ConfMan.getInt("audio_buffer_size");
if (samples > 0)
_samples = samples;
ConfMan.setInt("audio_buffer_size", (int)_samples);
debug("sample buffer size: %d", _samples);
ConfMan.flushToDisk();
_atariSampleBufferSize = _samples * 4;
_atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
if (!_atariSampleBuffer)
error("Failed to allocate memory in ST RAM");
_atariPhysicalSampleBuffer = _atariSampleBuffer;
_atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
Setmode(MODE_STEREO16);
Soundcmd(ADDERIN, MATIN);
Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
_samplesBuf = new uint8[_samples * 4];
_mixer = new Audio::MixerImpl(_outputRate, _samples);
_mixer->setReady(true);
@ -210,41 +189,28 @@ void AtariMixerManager::init() {
}
void AtariMixerManager::suspendAudio() {
if (s_audioNotAvailable)
return;
debug("suspendAudio");
Buffoper(0x00);
stopPlayback(kPlaybackStopped);
_audioSuspended = true;
}
int AtariMixerManager::resumeAudio() {
if (s_audioNotAvailable)
return 0;
debug("resumeAudio");
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
update();
_audioSuspended = false;
return 0;
}
bool AtariMixerManager::notifyEvent(const Common::Event &event) {
if (s_audioNotAvailable)
return false;
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
debug("silencing the mixer"); // TODO: is it for long enough?
memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
return false;
case Common::EVENT_MUTE:
_muted = !_muted;
debug("audio %s", _muted ? "off" : "on");
stopPlayback(kPlaybackStopped);
debug("silencing the mixer");
return false;
default:
[[fallthrough]];
@ -253,44 +219,67 @@ bool AtariMixerManager::notifyEvent(const Common::Event &event) {
return false;
}
void AtariMixerManager::startPlayback(PlaybackState playbackState) {
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
_playbackState = playbackState;
debug("playback started");
}
void AtariMixerManager::stopPlayback(PlaybackState playbackState) {
Buffoper(0x00);
_playbackState = playbackState;
debug("playback stopped");
}
void AtariMixerManager::update() {
if (_audioSuspended) {
return;
}
if (s_audioNotAvailable) {
static byte dummy[4];
_mixer->mixCallback(dummy, 0);
return;
}
assert(_mixer);
static bool loadSampleFlag = true;
byte *buf = nullptr;
uint32 processed = 0;
if (_playbackState == kPlaybackStopped) {
// playback stopped means that we are not playing anything (DMA
// pointer is not updating) but the mixer may have something available
processed = _mixer->mixCallback(_samplesBuf, _samples * 4);
SndBufPtr sPtr;
if (Buffptr(&sPtr) != 0)
return;
if (!loadSampleFlag) {
if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
buf = _atariLogicalSampleBuffer;
loadSampleFlag = !loadSampleFlag;
if (processed > 0) {
memcpy(_atariPhysicalSampleBuffer, _samplesBuf, processed * 4);
startPlayback(kPlayingFromPhysicalBuffer);
}
} else {
if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
buf = _atariPhysicalSampleBuffer;
loadSampleFlag = !loadSampleFlag;
SndBufPtr sPtr;
if (Buffptr(&sPtr) != 0) {
warning("Buffptr() failed");
return;
}
byte *buf = nullptr;
if (_playbackState == kPlayingFromPhysicalBuffer) {
if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
buf = _atariLogicalSampleBuffer;
_playbackState = kPlayingFromLogicalBuffer;
}
} else if (_playbackState == kPlayingFromLogicalBuffer) {
if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
buf = _atariPhysicalSampleBuffer;
_playbackState = kPlayingFromPhysicalBuffer;
}
}
if (buf) {
processed = _mixer->mixCallback(_samplesBuf, _samples * 4);
if (processed > 0) {
memcpy(buf, _samplesBuf, processed * 4);
} else {
stopPlayback(kPlaybackStopped);
}
}
}
if (buf != nullptr) {
assert(_mixer);
// generates stereo 16-bit samples
int processed = _mixer->mixCallback(_samplesBuf, _muted ? 0 : _samples * 4);
if (processed > 0) {
memcpy(buf, _samplesBuf, processed * 4);
} else {
memset(buf, 0, _atariSampleBufferSize);
}
if (processed > 0 && processed != _samples) {
warning("processed: %d, _samples: %d", processed, _samples);
}
}

View File

@ -43,6 +43,15 @@ public:
bool notifyEvent(const Common::Event &event) override;
private:
enum PlaybackState {
kPlaybackStopped,
kPlayingFromPhysicalBuffer,
kPlayingFromLogicalBuffer
};
void startPlayback(PlaybackState playbackState);
void stopPlayback(PlaybackState playbackState);
uint32 _outputRate;
uint32 _samples = 0;
uint8 *_samplesBuf = nullptr;
@ -52,7 +61,7 @@ private:
byte *_atariLogicalSampleBuffer = nullptr;
size_t _atariSampleBufferSize; // one buffer (logical/physical)
bool _muted = false;
PlaybackState _playbackState = kPlaybackStopped;
};
#endif

View File

@ -360,7 +360,8 @@ MODULE_OBJS += \
graphics/atari/atari_c2p-asm.o \
graphics/atari/atari-graphics.o \
graphics/atari/atari-graphics-asm.o \
mixer/atari/atari-mixer.o
mixer/atari/atari-mixer.o \
mixer/null/null-mixer.o
endif
ifeq ($(BACKEND),ds)

View File

@ -50,6 +50,7 @@
#include "backends/graphics/atari/atari-graphics.h"
#include "backends/keymapper/hardware-input.h"
#include "backends/mixer/atari/atari-mixer.h"
#include "backends/mixer/null/null-mixer.h"
#include "backends/mutex/null/null-mutex.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
@ -253,7 +254,24 @@ void OSystem_Atari::initBackend() {
atariEventSource->setGraphicsManager(atariGraphicsManager);
_mixerManager = new AtariMixerManager();
#ifdef DISABLE_FANCY_THEMES
// On the slim build force "STMIDI" as GM MIDI device, i.e. do not attempt
// to emulate anything by default. That prevents mixing silence and enable
// us to stop DMA playback which takes cycles especially on TT with STFA's
// emulation.
if (!ConfMan.hasKey("gm_device")) {
ConfMan.set("gm_device", "stmidi");
}
#endif
long cookie;
if (Getcookie(C__SND, &cookie) == C_FOUND && (cookie & SND_16BIT)) {
_mixerManager = new AtariMixerManager();
} else {
warning("Mixer manager requires 16-bit stereo mode, disabling");
_mixerManager = new NullMixerManager();
_useNullMixer = true;
}
// Setup and start mixer
_mixerManager->init();
@ -374,7 +392,10 @@ Common::String OSystem_Atari::getDefaultConfigFileName() {
void OSystem_Atari::update() {
((DefaultTimerManager *)_timerManager)->checkTimers();
((AtariMixerManager *)_mixerManager)->update();
if (_useNullMixer)
((NullMixerManager *)_mixerManager)->update();
else
((AtariMixerManager *)_mixerManager)->update();
}
OSystem *OSystem_Atari_create() {

View File

@ -53,6 +53,7 @@ private:
bool _videoInitialized = false;
bool _timerInitialized = false;
bool _useNullMixer = false;
};
#endif

View File

@ -81,9 +81,6 @@ Main features
Platform-specific features outside the GUI
------------------------------------------
Keyboard shortcut "CONTROL+u": immediate mute on/off toggle (disables also
sample mixing, contrary to what "Mute all" in the options does!)
Keyboard shortcut "CONTROL+ALT+a": immediate aspect ratio correction on/off
toggle.
@ -265,10 +262,10 @@ or "FM_medium_quality=true" into scummvm.ini if you want to experiment with a
better quality synthesis, otherwise the lowest quality will be used (applies
for MAME OPL only).
On the TT, in 95% of cases it makes sense to enable music only if you have a
native MIDI synthesizer (like mt32-pi: https://github.com/dwhinham/mt32-pi);
STFA is usually slow to mix samples, too => mute it (see below) or don't
install STFA (same effect).
On the TT, in 95% of cases it makes sense to use ScummVM only if you own a
native MIDI synthesizer (like mt32-pi: https://github.com/dwhinham/mt32-pi).
MIDI emulation is out of question and STFA is usually slow to mix samples, too
=> stick with games with MIDI sounds or at least don't install/enable STFA.
CD music slows everything down
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -283,26 +280,22 @@ rendering. Try to put "musdisk1.bun" and "musdisk2.bun" into a ramdisk (i.e.
u:/ram in FreeMiNT), you'll be pleasantly surprised with the performance boost
gained.
"Mute" vs. "Mute all" in GUI vs. "No music" in GUI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mute vs. "No music"
~~~~~~~~~~~~~~~~~~~
Not the same thing. "Mute" (available only via the shortcut CONTROL+u) generates
an event to which the sample mixer can react (i.e. stop mixing the silence...).
"Mute all" doesn't generate anything, it basically just lowers the volume of the
music to zero.
Currently ScummVM requires each backend to mix samples, even though they may
contain muted output (i.e. zeroes). This is because the progression of sample
playback tells ScummVM how much time has passed in e.g. an animation.
"No music" means using the null audio plugin which prevents generating any MIDI
music (and therefore avoiding the expensive synthesis emulation) but beware, it
doesn't affect CD (*.wav) playback at all!
doesn't affect CD (*.wav) playback at all! Same applies for speech and sfx.
So for the best performance, always choose "No music" in the GUI options when
the game contains MIDI tracks and "Mute" when the game contains a sampled
soundtrack.
Please note that it is not that bad, you surely can play The Secret of Monkey
Island with AdLib enabled (but the CD/talkie versions sound better and
are cheaper to play ;)).
The least amount of cycles is spent when:
- "No music" (or keep it default and choose a native MIDI device) is set in the
GUI options; this prevents MIDI sythesis of any kind
- all external audio files are deleted (typically *.wav); that way the mixer
wont have anything to mix. However beware, this is not allowed in every game!
Slow GUI
~~~~~~~~
@ -333,6 +326,9 @@ restricts features but also improves performance:
- overlay doesn't support alternative themes => faster loading time
- "STMIDI" driver is automatically enabled (i.e. MIDI emulation is never used
but still allows playing speech/sfx samples and/or CD audio)
Known issues
------------