fix: stereo sample downmix in track panners which causes the sampled sounds (both MIDI and audio tracks) are quieter than it should be

This commit is contained in:
Xiaohan-Tian
2026-05-24 00:04:19 -07:00
parent 7ee4a7458e
commit 77fb0e4c1f
7 changed files with 19 additions and 6 deletions
+2
View File
@@ -28,3 +28,5 @@ DEPLOYMENT.md
*.sln *.sln
*.sw? *.sw?
*.psd *.psd
audio-debug.html
src/audio-debug.ts
+2 -1
View File
@@ -4,6 +4,7 @@ import { FLUIDR3_INSTRUMENT_MAP } from '../../constants/generalMidiConstants';
import type { InstrumentType } from '../track/KGMidiTrack'; import type { InstrumentType } from '../track/KGMidiTrack';
import { KGToneBuffersPool } from './KGToneBuffersPool'; import { KGToneBuffersPool } from './KGToneBuffersPool';
import { KGToneSamplerFactory } from './KGToneSamplerFactory'; import { KGToneSamplerFactory } from './KGToneSamplerFactory';
import { createStereoTrackPanner } from './createStereoTrackPanner';
// InstrumentType is defined in KGMidiTrack and re-used here // InstrumentType is defined in KGMidiTrack and re-used here
@@ -100,7 +101,7 @@ export class KGAudioBus {
]); ]);
// Create the audio bus instance // Create the audio bus instance
const panner = new Tone.Panner(pan); const panner = createStereoTrackPanner(pan);
sampler.connect(panner); sampler.connect(panner);
const audioBus = new KGAudioBus(sampler, audioBuffers, instrument, panner, volume, pan, muted, solo); const audioBus = new KGAudioBus(sampler, audioBuffers, instrument, panner, volume, pan, muted, solo);
+2 -1
View File
@@ -1,5 +1,6 @@
import * as Tone from 'tone'; import * as Tone from 'tone';
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants'; import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
import { createStereoTrackPanner } from './createStereoTrackPanner';
/** /**
* KGAudioPlayerBus - Represents an audio playback bus for a track. * KGAudioPlayerBus - Represents an audio playback bus for a track.
@@ -61,7 +62,7 @@ export class KGAudioPlayerBus {
): Promise<KGAudioPlayerBus> { ): Promise<KGAudioPlayerBus> {
try { try {
const gainNode = new Tone.Gain(1); const gainNode = new Tone.Gain(1);
const pannerNode = new Tone.Panner(pan); const pannerNode = createStereoTrackPanner(pan);
gainNode.connect(pannerNode); gainNode.connect(pannerNode);
const bus = new KGAudioPlayerBus(gainNode, pannerNode, volume, pan, muted, solo); const bus = new KGAudioPlayerBus(gainNode, pannerNode, volume, pan, muted, solo);
console.log('KGAudioPlayerBus created successfully'); console.log('KGAudioPlayerBus created successfully');
@@ -29,6 +29,7 @@ import { beatRangeToSeconds, beatToSeconds, findGlobalTrackByType, getEffectiveB
import { GlobalTrackType } from '../global-track'; import { GlobalTrackType } from '../global-track';
import { ConfigManager } from '../config/ConfigManager'; import { ConfigManager } from '../config/ConfigManager';
import { Mp3Encoder } from '@breezystack/lamejs'; import { Mp3Encoder } from '@breezystack/lamejs';
import { createStereoTrackPanner } from './createStereoTrackPanner';
export interface RenderOptions { export interface RenderOptions {
sampleRate?: number; // default 44100 sampleRate?: number; // default 44100
@@ -332,7 +333,7 @@ export class KGOfflineRenderer {
// Track volumes are stored in dB across the app, with 0 meaning unity gain. // Track volumes are stored in dB across the app, with 0 meaning unity gain.
sampler.volume.value = 0; sampler.volume.value = 0;
const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted)); const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted));
const trackPanner = new Tone.Panner(0); const trackPanner = createStereoTrackPanner(0);
sampler.connect(trackGain); sampler.connect(trackGain);
trackGain.connect(trackPanner); trackGain.connect(trackPanner);
trackPanner.connect(masterGain); trackPanner.connect(masterGain);
@@ -439,7 +440,7 @@ export class KGOfflineRenderer {
if (!shouldPlay(trackInfo, hasSoloedTracks)) continue; if (!shouldPlay(trackInfo, hasSoloedTracks)) continue;
const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted)); const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted));
const trackPanner = new Tone.Panner(0); const trackPanner = createStereoTrackPanner(0);
trackGain.connect(trackPanner); trackGain.connect(trackPanner);
trackPanner.connect(masterGain); trackPanner.connect(masterGain);
applyOfflineTrackAutomation( applyOfflineTrackAutomation(
@@ -0,0 +1,8 @@
import * as Tone from 'tone';
export function createStereoTrackPanner(pan: number = 0): Tone.Panner {
return new Tone.Panner({
pan,
channelCount: 2,
});
}