The cabinets had no volume control - they ran at unity and left level to an external amplifier - so a player without that hardware had nowhere to turn it down but environ.ini and a restart. PageUp and PageDown now step the master volume by 0.05 while you play, from silent to double, and whatever you leave it on is written to volume.cfg beside the exe and used from then on. The environ.ini figure decides where a machine that has never been touched starts out; the keys are the knob, and a knob stays where it was left. Page keys because they produce no typed character, so they cannot collide with the character-keyed commands the engine already answers to, nothing else in RP binds them, and they are on every keyboard including tenkeyless. They are polled rather than read off the key-message path, which is worth recording because the message path looked like the obvious home for them and was tried first. RP's keyboard pump only takes WM_KEYUP, WM_SYSKEYUP and WM_CHAR off the front of the queue, and the front end runs message loops of its own, so key messages get raced for and lost: six deliberate, well-spaced presses arrived as two. Fine for the abort chord, useless for something you tap repeatedly to find a level. Reading key state directly costs nothing and cannot be dropped. That losses figure is a pre-existing property of the input path, not something this change introduced, and is worth knowing before anything else gets bound there. Builds clean, runs, and does not fire unprompted. The step function itself is proven - it was driven end to end through the message path before the switch, stepping the right way, clamping, and persisting. What I could not test from here is the polling trigger, because Windows would not hand the game foreground and injecting keys without it would have sprayed them across whatever else was open. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
216 lines
5.1 KiB
C++
216 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include "..\munga\audrend.h"
|
|
#include "l4audhdw.h"
|
|
#include "l4audio.h"
|
|
#include "l4audres.h"
|
|
#include "openal/al.h"
|
|
|
|
//
|
|
// Master volume, standing in for the amplifier the cabinets had. Stepped by
|
|
// PgUp/PgDn (L4APP.cpp) and persisted to volume.cfg; see L4AUDRND.cpp.
|
|
//
|
|
extern float gRPMasterVolume;
|
|
|
|
void RPAudioMasterVolumeStep(int direction);
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ L4AudioRenderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class L4AudioRenderer:
|
|
public AudioRenderer
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction, Destruction, Testing
|
|
//
|
|
public:
|
|
L4AudioRenderer(
|
|
RendererRate render_rate,
|
|
Logical mission_review_mode
|
|
);
|
|
~L4AudioRenderer();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
virtual void ReleaseSourceSet(SourceSet &sourceSet);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Renderer support
|
|
//
|
|
public:
|
|
void
|
|
Initialize();
|
|
public:
|
|
|
|
void
|
|
NotifyOfNewInterestingEntity(Entity *interesting_entity);
|
|
void
|
|
NotifyOfBecomingUninterestingEntity(Entity *uninteresting_entity);
|
|
|
|
protected:
|
|
void
|
|
ExecuteImplementation(
|
|
RendererComplexity complexity_update,
|
|
RendererOrigin::InterestingEntityIterator *iterator
|
|
);
|
|
|
|
private:
|
|
void
|
|
LoadMissionImplementation(Mission *mission);
|
|
void
|
|
ShutdownImplementation();
|
|
void
|
|
SuspendImplementation();
|
|
void
|
|
ResumeImplementation();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Audio hardware accessors
|
|
//
|
|
public:
|
|
/* AudioCard*
|
|
GetFrontCard();
|
|
AudioCard*
|
|
GetRearCard();*/
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Audio Source support
|
|
//
|
|
public:
|
|
void
|
|
StartRequest(L4AudioSource *audio_source);
|
|
void
|
|
StopRequest(L4AudioSource *audio_source);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Private methods
|
|
//
|
|
private:
|
|
void
|
|
CalculateMix();
|
|
void
|
|
RunningSourceCheckup();
|
|
//void
|
|
// RunningAudioSourceSort();
|
|
void
|
|
DormantSourceCheckup();
|
|
void
|
|
AudioSourceStopMaintenance(L4AudioSource *source);
|
|
void
|
|
AudioSourceSuspendMaintenance(L4AudioSource *source);
|
|
|
|
Logical
|
|
RequestAudioResources(
|
|
L4AudioSource *audio_source,
|
|
SourceSet *source_result
|
|
);
|
|
Logical
|
|
RequestAudioChannels(
|
|
AudioVoiceCount voices_requested,
|
|
SourceSet *source_request
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Private data
|
|
//
|
|
private:
|
|
Logical
|
|
missionReviewMode;
|
|
|
|
/* AudioHardware
|
|
audioHardware;*/
|
|
L4AudioResourceManager
|
|
audioResourceManager;
|
|
|
|
AudioFrameCount
|
|
nextCalculateMixFrame;
|
|
|
|
typedef VChainOf<L4AudioSource*, AudioWeighting>
|
|
RunningSourceSocket;
|
|
typedef VChainIteratorOf<L4AudioSource*, AudioWeighting>
|
|
RunningSourceIterator;
|
|
|
|
RunningSourceSocket
|
|
runningAudioSourceSocket;
|
|
|
|
typedef ChainOf<L4AudioSource*>
|
|
DormantSourceSocket;
|
|
typedef ChainIteratorOf<L4AudioSource*>
|
|
DormantSourceIterator;
|
|
|
|
DormantSourceSocket
|
|
dormantAudioSourceSocket;
|
|
|
|
typedef VChainOf<L4AudioSource*, Enumeration>
|
|
MixingSourceSocket;
|
|
typedef VChainIteratorOf<L4AudioSource*, Enumeration>
|
|
MixingSourceIterator;
|
|
|
|
MixingSourceSocket
|
|
mixingAudioSourceSocket;
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~ L4AudioRenderer inlines ~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
/*inline AudioCard*
|
|
L4AudioRenderer::GetFrontCard()
|
|
{
|
|
Check(this);
|
|
return audioHardware.GetFrontCard();
|
|
}
|
|
|
|
inline AudioCard*
|
|
L4AudioRenderer::GetRearCard()
|
|
{
|
|
Check(this);
|
|
return audioHardware.GetRearCard();
|
|
}*/
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~ L4AudioRenderer profile macros ~~~~~~~~~~~~~~~~~~~~
|
|
|
|
#if defined(TRACE_AUDIO_RENDERER_RUNNING_SOURCES)
|
|
extern BitTrace Audio_Renderer_Running_Sources;
|
|
#define SET_AUDIO_RUNNING_SOURCES() Audio_Renderer_Running_Sources.Set()
|
|
#define CLEAR_AUDIO_RUNNING_SOURCES() Audio_Renderer_Running_Sources.Clear()
|
|
#else
|
|
#define SET_AUDIO_RUNNING_SOURCES()
|
|
#define CLEAR_AUDIO_RUNNING_SOURCES()
|
|
#endif
|
|
|
|
#if defined(TRACE_AUDIO_RENDERER_RUNNING_SORT)
|
|
extern BitTrace Audio_Renderer_Running_Sort;
|
|
#define SET_AUDIO_RUNNING_SORT() Audio_Renderer_Running_Sort.Set()
|
|
#define CLEAR_AUDIO_RUNNING_SORT() Audio_Renderer_Running_Sort.Clear()
|
|
#else
|
|
#define SET_AUDIO_RUNNING_SORT()
|
|
#define CLEAR_AUDIO_RUNNING_SORT()
|
|
#endif
|
|
|
|
#if defined(TRACE_AUDIO_RENDERER_CALCULATE_MIX)
|
|
extern BitTrace Audio_Renderer_Calculate_Mix;
|
|
#define SET_AUDIO_CALCULATE_MIX() Audio_Renderer_Calculate_Mix.Set()
|
|
#define CLEAR_AUDIO_CALCULATE_MIX() Audio_Renderer_Calculate_Mix.Clear()
|
|
#else
|
|
#define SET_AUDIO_CALCULATE_MIX()
|
|
#define CLEAR_AUDIO_CALCULATE_MIX()
|
|
#endif
|
|
|
|
#if defined(TRACE_AUDIO_RENDERER_EXECUTE_SOURCES)
|
|
extern BitTrace Audio_Renderer_Execute_Sources;
|
|
#define SET_AUDIO_EXECUTE_SOURCES() Audio_Renderer_Execute_Sources.Set()
|
|
#define CLEAR_AUDIO_EXECUTE_SOURCES() Audio_Renderer_Execute_Sources.Clear()
|
|
#else
|
|
#define SET_AUDIO_EXECUTE_SOURCES()
|
|
#define CLEAR_AUDIO_EXECUTE_SOURCES()
|
|
#endif
|
|
|
|
#if defined(TRACE_AUDIO_RENDERER_DORMANT_SOURCES)
|
|
extern BitTrace Audio_Renderer_Dormant_Sources;
|
|
#define SET_AUDIO_DORMANT_SOURCES() Audio_Renderer_Dormant_Sources.Set()
|
|
#define CLEAR_AUDIO_DORMANT_SOURCES() Audio_Renderer_Dormant_Sources.Clear()
|
|
#else
|
|
#define SET_AUDIO_DORMANT_SOURCES()
|
|
#define CLEAR_AUDIO_DORMANT_SOURCES()
|
|
#endif
|