Audio: implement NOTE->PITCH + control pitch -- the AL_PITCH was never applied (task #50)
The whole pitch system existed but was discarded: NoteAudioHandler captured the
MIDI note, ExecuteModel computed relativePitch from the control-chain cents --
and NOTHING ever called alSourcef(AL_PITCH). Every sample played at root.
Consequences fixed:
- The load-time 'chirping' ambience: an authored looped sequence (div=120
tempo=160, note 51 events on bank1:83) plays a rhythmic tick pitched ~9
semitones DOWN; at root it was a high click ('chirp'). Identified live via
the new BT_AUDIO_DUMP playing-source tape + user ear-match at cadence.
- Engine now revs: EngineMotor pitch rides the throttle (measured 1.0 -> 1.12).
- All sequence-authored patterns (alarms/klaxons/ambience) regain their pitch.
Implementation: BTNotePitchFactor(note) = 2^((note-60)/12); applied at all 3
patch-source StartImplementations (fresh attach) and all 3 ExecuteModels
(combined with the control-chain relativePitch, clamped 0.5..2.0 as before).
Uses the existing AudioSource::GetCurrentNoteValue().
Also: [seqcfg] sequence-config dump, g_bufferNames + BT_AUDIO_DUMP live tape
(1/s: every playing AL source with sample name/gain/pitch/loop),
tools/soundboard.py updated mapping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e017f257a5
commit
37d4554440
@@ -157,6 +157,32 @@ void
|
||||
headVelocity.MultiplyByInverse(this->GetHeadEntity()->GetWorldLinearVelocity(), this->GetHeadEntity()->localToWorld);
|
||||
alListener3f(AL_VELOCITY, -headVelocity.x, -headVelocity.y, -headVelocity.z);
|
||||
|
||||
// LIVE-PLAYING DUMP (BT_AUDIO_DUMP): once a second list every playing AL
|
||||
// source with its sample name / gain / pitch / loop -- catches "mystery
|
||||
// sounds" (wrong sample, wrong pitch, chopped) red-handed.
|
||||
if (getenv("BT_AUDIO_DUMP")) {
|
||||
static long s_dumpTick = 0;
|
||||
if ((++s_dumpTick % 45) == 0) {
|
||||
extern ALuint *g_buffers; extern int g_numBuffers; extern const char *g_bufferNames[512];
|
||||
for (ALuint sid = 1; sid <= 40; ++sid) {
|
||||
if (!alIsSource(sid)) continue;
|
||||
ALint st = 0; alGetSourcei(sid, AL_SOURCE_STATE, &st);
|
||||
if (st != AL_PLAYING) continue;
|
||||
ALint buf = 0, looping = 0; ALfloat gain = 0, pitch = 0;
|
||||
alGetSourcei(sid, AL_BUFFER, &buf);
|
||||
alGetSourcei(sid, AL_LOOPING, &looping);
|
||||
alGetSourcef(sid, AL_GAIN, &gain);
|
||||
alGetSourcef(sid, AL_PITCH, &pitch);
|
||||
const char *nm = "?";
|
||||
for (int b = 0; b < g_numBuffers && b < 512; ++b)
|
||||
if ((ALint)g_buffers[b] == buf) { nm = g_bufferNames[b] ? g_bufferNames[b] : "?"; break; }
|
||||
DEBUG_STREAM << "[playing] src=" << sid << " " << nm
|
||||
<< " gain=" << gain << " pitch=" << pitch
|
||||
<< " loop=" << looping << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Get the entity
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include "mungal4.h"
|
||||
#pragma hdrstop
|
||||
@@ -10,6 +11,18 @@
|
||||
#include "..\munga\player.h"
|
||||
#include "..\rp\vtv.h"
|
||||
|
||||
|
||||
// NOTE -> PITCH (task #50): the AWE32 played every patch at the requested MIDI
|
||||
// note relative to the sample root (60); sequences author notes (klaxon/ambience
|
||||
// rhythms are PITCHED patterns). The port captured noteValue but never applied
|
||||
// any pitch to the AL sources -- everything played at root (the "chirping"
|
||||
// ambience: an authored deep tick at note 51 sounded as a high click). Apply
|
||||
// pitch = 2^((note-60)/12) x the control-chain cents offset at start + per frame.
|
||||
static inline float BTNotePitchFactor(int note_value)
|
||||
{
|
||||
return (float)pow(2.0, ((double)note_value - 60.0) / 12.0);
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//####################### L4AudioSpatialization #########################
|
||||
//#############################################################################
|
||||
@@ -924,6 +937,12 @@ void
|
||||
patch_resource->SetDistance(GetDistanceToSource());
|
||||
patch_resource->SetupPatch(channelSet);
|
||||
|
||||
{ // apply the requested note's pitch to the freshly attached sources
|
||||
float note_pitch = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, note_pitch);
|
||||
}
|
||||
|
||||
//
|
||||
// Set the channel to default control values
|
||||
//
|
||||
@@ -1034,6 +1053,11 @@ void
|
||||
pitch_offset = CalculateSourcePitchOffset();
|
||||
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
||||
Clamp(relativePitch,0.5,2.0);
|
||||
{ // apply the combined control-chain + note pitch per frame
|
||||
float _np = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, (float)relativePitch * _np);
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -1210,6 +1234,12 @@ void
|
||||
patch_resource->SetDistance(GetDistanceToSource());
|
||||
patch_resource->SetupPatch(channelSet);
|
||||
|
||||
{ // apply the requested note's pitch to the freshly attached sources
|
||||
float note_pitch = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, note_pitch);
|
||||
}
|
||||
|
||||
/*patch_resource->SetDistance(GetDistanceToSource());
|
||||
for (i = 0; i < AudioChannelSetSize; i++)
|
||||
{
|
||||
@@ -1411,6 +1441,11 @@ void
|
||||
|
||||
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
||||
Clamp(relativePitch,0.5,2.0);
|
||||
{ // apply the combined control-chain + note pitch per frame
|
||||
float _np = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, (float)relativePitch * _np);
|
||||
}
|
||||
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sp=0; if ((s_sp++ % 120) == 0)
|
||||
DEBUG_STREAM << "[spatial] dyn src=" << (channelSet.count>0?channelSet.sources[0]:0)
|
||||
@@ -1704,6 +1739,12 @@ void
|
||||
Check(patch_resource);
|
||||
patch_resource->SetDistance(GetDistanceToSource());
|
||||
patch_resource->SetupPatch(channelSet);
|
||||
|
||||
{ // apply the requested note's pitch to the freshly attached sources
|
||||
float note_pitch = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, note_pitch);
|
||||
}
|
||||
/*for (i = 0; i < AudioChannelSetSize; i++)
|
||||
{
|
||||
if ((channel = channelSet.GetNth(i)) != NULL)
|
||||
@@ -1931,6 +1972,11 @@ void
|
||||
pitch_offset = CalculateSourcePitchOffset();
|
||||
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
||||
Clamp(relativePitch,0.5,2.0);
|
||||
{ // apply the combined control-chain + note pitch per frame
|
||||
float _np = BTNotePitchFactor((int)GetCurrentNoteValue());
|
||||
for (int _i = 0; _i < channelSet.count; ++_i)
|
||||
alSourcef(channelSet.sources[_i], AL_PITCH, (float)relativePitch * _np);
|
||||
}
|
||||
|
||||
Vector3D relative_position;
|
||||
Vector3D relative_velocity;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
ALuint *g_buffers;
|
||||
int g_numBuffers;
|
||||
const char *g_bufferNames[512]; // bufferInd -> sample file (diag: the live-playing dump)
|
||||
int g_curAudioWatcherClass = 0;
|
||||
|
||||
//
|
||||
@@ -671,6 +672,7 @@ void
|
||||
|
||||
//Feed the buffer with the real PCM sample data
|
||||
alBufferData(g_buffers[bufferInd], format, data, size, wavRate);
|
||||
if (bufferInd < 512) g_bufferNames[bufferInd] = info.file;
|
||||
if (getenv("BT_AUDIO_LOG") && bufferInd < 3)
|
||||
DEBUG_STREAM << "[audio] loaded buf" << bufferInd << " " << info.file
|
||||
<< " ch=" << wavCh << " bits=" << wavBits << " rate=" << wavRate
|
||||
|
||||
Reference in New Issue
Block a user