The cabinets ran the game at unity and shaped volume and tone outside it, in an external amplifier and a 3-way crossover. That is why there is no master volume anywhere in the original code and none in AUDIO.INI - an operator turned a knob on an amp. A desktop player has no amp and no crossover, and the recovered soundbanks are a good deal livelier than what 4.12 shipped with, so the game has to offer the two controls the pod got from hardware. RP412AUDIOVOLUME, 0.0 to 4.0, is the amplifier: a listener gain, which the port had never set at all. RP412AUDIOBASS, 0.0 to 1.0, is the crossover's low band. Both default to leaving the mix exactly as the pod played it, so neither changes anything for anyone who does not go looking. The bass trim is not a filter, and the reason is worth writing down: the OpenAL we ship is Creative's, not OpenAL Soft, and it implements only AL_FILTER_LOWPASS. It rejects highpass and bandpass outright. A bandpass would have been the tidy answer, carrying the authored brightness model on GAINHF and the trim on GAINLF across the single direct filter a source gets. It is not on offer. So the trim scales sample data as it loads, which suits how this low end is actually built: the weight lives in discrete deep layer zones whose per-zone tuning bakes out to a very low playback rate - thirteen zones below 8kHz, three to five octaves under their recorded pitch, against four fifths of the set at 22kHz and up. Baked rate is a dependable proxy for band, so pulling down the low-rate zones is a real low-band trim and not a blunt cut. It eases in below 22kHz and reaches full depth at 5.5kHz. Caught while building this, and the reason for the probe: EFX_Initialize checks alGetError after configuring the scratch filter, so asking for a filter type the driver refuses leaves an error pending and takes the entire bridge down - reverb included. The bandpass attempt did precisely that and would have silently killed the reverb and brightness work. Initialize now survives losing the filter and says so. Builds clean, runs with both knobs set and with neither. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
170 lines
4.4 KiB
C++
170 lines
4.4 KiB
C++
#pragma once
|
|
|
|
#include "..\munga\objstrm.h"
|
|
#include "..\munga\entity.h"
|
|
#include "..\munga\audio.h"
|
|
#include "openal/al.h"
|
|
|
|
ALuint AL_getBuffer(int index);
|
|
extern ALuint *g_buffers;
|
|
extern int g_numBuffers;
|
|
|
|
//
|
|
// RP412AUDIOBASS low-band trim, applied to sample data as buffers are loaded.
|
|
// See the comment block in L4AUDRES.cpp for why it lives here and not in EFX.
|
|
//
|
|
void RPApplyBassTrim(char *data, int bytes, unsigned long format_bits, ALsizei rate);
|
|
|
|
|
|
//class AudioHardware;
|
|
|
|
//##########################################################################
|
|
//###################### AudioObjectStream ###########################
|
|
//##########################################################################
|
|
|
|
class AudioObjectStream:
|
|
public PlugStream
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction, Destruction and testing
|
|
//
|
|
public:
|
|
AudioObjectStream();
|
|
AudioObjectStream(
|
|
ResourceDescription *resource_description,
|
|
Entity *entity
|
|
);
|
|
~AudioObjectStream();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Implementations
|
|
//
|
|
private:
|
|
RegisteredClass*
|
|
MakeObjectImplementation(Enumeration class_ID);
|
|
|
|
void
|
|
CreatedObjectImplementation(
|
|
RegisteredClass *object,
|
|
ObjectID object_ID
|
|
);
|
|
|
|
void
|
|
BuildFromPageImplementation(
|
|
NameList *entry_list,
|
|
Enumeration class_ID,
|
|
ObjectID object_ID
|
|
);
|
|
|
|
void
|
|
BuiltFromPageImplementation(
|
|
Enumeration class_ID,
|
|
ObjectID object_ID,
|
|
const CString &object_name_string
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Private data
|
|
//
|
|
private:
|
|
Entity *entity;
|
|
};
|
|
|
|
//##########################################################################
|
|
//#################### L4AudioResourceManager ########################
|
|
//##########################################################################
|
|
|
|
class L4AudioResourceManager:
|
|
public Node
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction, Destruction, Testing
|
|
//
|
|
public:
|
|
L4AudioResourceManager();
|
|
~L4AudioResourceManager();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Static audio object methods
|
|
//
|
|
public:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// PreloadResources
|
|
//--------------------------------------------------------------------
|
|
//
|
|
void
|
|
PreloadResources(
|
|
NotationFile *notation_file
|
|
);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// UnloadResources
|
|
//--------------------------------------------------------------------
|
|
//
|
|
void
|
|
UnloadResources(
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Static audio object methods - tool support
|
|
//
|
|
public:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// CreateStaticAudioStreamResource
|
|
//--------------------------------------------------------------------
|
|
//
|
|
static ResourceDescription::ResourceID
|
|
CreateStaticAudioStreamResource(
|
|
ResourceFile *resource_file
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Dynamic audio object methods
|
|
//
|
|
public:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// CreateEntityAudioObjects
|
|
//--------------------------------------------------------------------
|
|
//
|
|
void
|
|
CreateEntityAudioObjects(
|
|
Entity *entity,
|
|
AudioRepresentation audio_representation
|
|
);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// DestroyEntityAudioObjects
|
|
//--------------------------------------------------------------------
|
|
//
|
|
void
|
|
DestroyEntityAudioObjects(Entity *entity);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Dynamic audio object methods - tool support
|
|
//
|
|
public:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// CreateModelAudioStreamResource
|
|
//--------------------------------------------------------------------
|
|
//
|
|
static ResourceDescription::ResourceID
|
|
CreateModelAudioStreamResource(
|
|
ResourceFile *resource_file,
|
|
const char *model_name,
|
|
NotationFile *model_file,
|
|
const ResourceDirectories *directories
|
|
);
|
|
};
|