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
*.sw?
*.psd
audio-debug.html
src/audio-debug.ts
+1 -1
View File
@@ -243,4 +243,4 @@ const PianoKeys: React.FC<PianoKeysProps> = ({ activeRegion }) => {
);
};
export default PianoKeys;
export default PianoKeys;
+2 -1
View File
@@ -4,6 +4,7 @@ import { FLUIDR3_INSTRUMENT_MAP } from '../../constants/generalMidiConstants';
import type { InstrumentType } from '../track/KGMidiTrack';
import { KGToneBuffersPool } from './KGToneBuffersPool';
import { KGToneSamplerFactory } from './KGToneSamplerFactory';
import { createStereoTrackPanner } from './createStereoTrackPanner';
// InstrumentType is defined in KGMidiTrack and re-used here
@@ -100,7 +101,7 @@ export class KGAudioBus {
]);
// Create the audio bus instance
const panner = new Tone.Panner(pan);
const panner = createStereoTrackPanner(pan);
sampler.connect(panner);
const audioBus = new KGAudioBus(sampler, audioBuffers, instrument, panner, volume, pan, muted, solo);
+1 -1
View File
@@ -953,7 +953,7 @@ export class KGAudioInterface {
const normalizedVelocity = velocity / 127; // Normalize to 0-1
const triggerTime = time ?? Tone.now();
this.applyTrackAutomationForCurrentBeat(trackId);
// Check if track should play considering solo logic
const hasSoloedTracks = this.hasSoloedTracks();
if (audioBus.shouldPlayWithSolo(hasSoloedTracks)) {
+2 -1
View File
@@ -1,5 +1,6 @@
import * as Tone from 'tone';
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
import { createStereoTrackPanner } from './createStereoTrackPanner';
/**
* KGAudioPlayerBus - Represents an audio playback bus for a track.
@@ -61,7 +62,7 @@ export class KGAudioPlayerBus {
): Promise<KGAudioPlayerBus> {
try {
const gainNode = new Tone.Gain(1);
const pannerNode = new Tone.Panner(pan);
const pannerNode = createStereoTrackPanner(pan);
gainNode.connect(pannerNode);
const bus = new KGAudioPlayerBus(gainNode, pannerNode, volume, pan, muted, solo);
console.log('KGAudioPlayerBus created successfully');
@@ -29,6 +29,7 @@ import { beatRangeToSeconds, beatToSeconds, findGlobalTrackByType, getEffectiveB
import { GlobalTrackType } from '../global-track';
import { ConfigManager } from '../config/ConfigManager';
import { Mp3Encoder } from '@breezystack/lamejs';
import { createStereoTrackPanner } from './createStereoTrackPanner';
export interface RenderOptions {
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.
sampler.volume.value = 0;
const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted));
const trackPanner = new Tone.Panner(0);
const trackPanner = createStereoTrackPanner(0);
sampler.connect(trackGain);
trackGain.connect(trackPanner);
trackPanner.connect(masterGain);
@@ -439,7 +440,7 @@ export class KGOfflineRenderer {
if (!shouldPlay(trackInfo, hasSoloedTracks)) continue;
const trackGain = new Tone.Gain(getOfflineTrackGain(trackInfo.volume, trackInfo.muted));
const trackPanner = new Tone.Panner(0);
const trackPanner = createStereoTrackPanner(0);
trackGain.connect(trackPanner);
trackPanner.connect(masterGain);
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,
});
}