layers, baked tuning, loop regions, release fades Extractor rewrite (tools/sf2extract.py): every sample-bearing instrument zone becomes a SAMPLEINFO slot -- 603 zones / 241 presets (68/115 + 94/126 multi- zone, matching the audit exactly). Per zone: keyRange(43), sampleModes(54), SBK samplePitch(55) + rootKey(58) + coarse/fineTune(51/52), attenuation(48, INVERTED SBK scale, 0.375 dB/step [T3], baked into the PCM), releaseVolEnv(38), pan(17), shdr loop region. F2 pitch (algebraically exact): WAV rate = round(44100 * 2^(((6000 - rootCents) + tune)/1200)) -- EMU8000 v1 base 44100. Cross-checks: FootFall 17300 Hz (the audit's +4.2 st), MissileLoaded low zone 88200 (-24 st), Warnings01 8-way klaxon split w/ 3 looped zones, Death01 162 Hz extremes. F1 zone selection: SetupPatch/PlayNote take the authored note; attach/play only zones whose [keyLo,keyHi] contains it (detach the rest so a rewound source can't replay a stale buffer). Live-verified: LaserLoaded/ MissileLoaded note 36 -> low clunk zone, note 84 -> high blip zone (pitch 4); LaserCFire plays all 3 authored layers incl the looping sustain. Stereo-pair zones pan via listener-relative AL_POSITION (distance model is AL_NONE). MAX_PRESET_SAMPLES=25 (AllExplosion); fixed PRESET_isImplemented's >=5 bound. F13 loops + releases: authored [loopStart,loopEnd] applied via AL_SOFT_loop_points at buffer load (0 rejections; kills the latent boom-loop on MechExplosion's 1.5% sustain slice + the ~2.4 Hz LaserBSustain wrap tick); StopNote now honors the authored releaseVolEnv (1.1-3.9 s on ~20 looping presets) with a dB-linear fade serviced from AudioHead::Execute; restarts reclaim fading sources. One-shots keep the instant stop (faithful). Regression (40s drive+fire): stable, loop points accepted, key-splits + layers verified in the delivery trace, chirp still dead, footfalls fire. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
1.1 KiB
C++
53 lines
1.1 KiB
C++
#include "L4AUDLVL.h"
|
|
|
|
bool PRESET_isImplemented(int bank, int presetn)
|
|
{
|
|
PRESETINFO preset = allPresets[bank-1][presetn];
|
|
|
|
if (preset.sampleNum <= 0 || preset.sampleNum > MAX_PRESET_SAMPLES)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i=0; i < preset.sampleNum; i++)
|
|
{
|
|
if (preset.samples[i].implemented)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int PRESET_getNumSamples(int bank, int preset)
|
|
{
|
|
return allPresets[bank-1][preset].sampleNum;
|
|
}
|
|
|
|
SAMPLEINFO PRESET_getSampleInfo(int bank, int preset, int sampleInd)
|
|
{
|
|
if (sampleInd < 0 || sampleInd >= allPresets[bank-1][preset].sampleNum)
|
|
{
|
|
SAMPLEINFO none;
|
|
none.bufferIndex = -1;
|
|
none.implemented = false;
|
|
none.file = "";
|
|
none.chan = SampleChannel::CHANNEL_CENTER;
|
|
none.loop = SampleLoop::LoopAtWill;
|
|
none.keyLo = 0;
|
|
none.keyHi = 127;
|
|
none.loopStart = 0;
|
|
none.loopEnd = 0;
|
|
none.releaseSec = 0.0f;
|
|
return none;
|
|
}
|
|
|
|
return allPresets[bank-1][preset].samples[sampleInd];
|
|
}
|
|
|
|
void PRESET_setBufferIndex(int bank, int preset, int sampleInd, int index)
|
|
{
|
|
allPresets[bank-1][preset].samples[sampleInd].bufferIndex = index;
|
|
}
|