feat: added playback delay configuration

This commit is contained in:
Xiaohan-Tian
2025-12-21 20:11:27 -08:00
parent aadf9e06df
commit eaee036fc2
5 changed files with 91 additions and 16 deletions
+11 -1
View File
@@ -320,9 +320,19 @@ export class KGCore {
// Calculate current playhead position based on elapsed time
const elapsedMs = performance.now() - this.playbackStartTime;
// Get playback delay from config
const configManager = ConfigManager.instance();
const playbackDelaySeconds = (configManager.get('audio.playback_delay') as number) ?? 0.2;
const playbackDelayMs = playbackDelaySeconds * 1000;
// Subtract the delay from elapsed time for visual sync
// During the initial delay period, playhead stays at start position
const adjustedElapsedMs = Math.max(0, elapsedMs - playbackDelayMs);
const bpm = this.currentProject.getBpm();
const beatsPerMs = bpm / (60 * 1000);
const newPosition = this.playbackStartPosition + (elapsedMs * beatsPerMs);
const newPosition = this.playbackStartPosition + (adjustedElapsedMs * beatsPerMs);
// Stop playback at the end of project (maxBars)
const maxBars = this.currentProject.getMaxBars();
+14 -9
View File
@@ -64,8 +64,10 @@ export class KGAudioInterface {
}
try {
const configManager = ConfigManager.instance();
// Reduce lookahead time to 0.05 seconds to improve MIDI input responsiveness
Tone.getContext().lookAhead = 0.05;
Tone.getContext().lookAhead = configManager.get('audio.lookahead_time') as number;
// Set up master gain for volume control
this.masterGain = new Tone.Gain(this.masterVolume).toDestination();
@@ -75,7 +77,6 @@ export class KGAudioInterface {
Tone.Transport.timeSignature = [TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.numerator, TIME_CONSTANTS.DEFAULT_TIME_SIGNATURE.denominator]; // Default time signature
// Check config and setup audio capture if enabled
const configManager = ConfigManager.instance();
const enableCapture = configManager.get('audio.enable_audio_capture_for_screen_sharing') as boolean;
if (enableCapture) {
@@ -253,7 +254,11 @@ export class KGAudioInterface {
this.clearScheduledEvents();
console.log("Preparing playback");
// Get playback delay from ConfigManager
const configManager = ConfigManager.instance();
const playbackDelay = (configManager.get('audio.playback_delay') as number) ?? 0.2;
try {
// Set project BPM and time signature FIRST (this affects timing calculations)
Tone.Transport.bpm.value = project.getBpm();
@@ -295,21 +300,21 @@ export class KGAudioInterface {
// Convert beats to Tone.js time format for scheduling
const noteStartTime = this.beatsToToneTime(noteStartBeat);
const noteDuration = this.beatsToToneTime(noteDurationBeats);
// Convert MIDI note number to note name
const noteName = pitchToNoteNameString(note.getPitch());
const velocity = note.getVelocity() / 127; // Normalize to 0-1
console.log(
`Scheduling note ${noteName} at beat ${Number(noteStartBeat.toFixed ? noteStartBeat.toFixed(3) : noteStartBeat.toLocaleString(undefined, {maximumFractionDigits: 3}))}, Tone time: ${Number(Number(noteStartTime).toFixed(3))}, duration: ${Number(Number(noteDuration).toFixed(3))}`
`Scheduling note ${noteName} at beat ${Number(noteStartBeat.toFixed ? noteStartBeat.toFixed(3) : noteStartBeat.toLocaleString(undefined, {maximumFractionDigits: 3}))}, Tone time: ${Number(Number(noteStartTime).toFixed(3))}, duration: ${Number(Number(noteDuration).toFixed(3))}, delay: ${playbackDelay}s`
);
// Schedule the note
// Schedule the note with delay offset
const eventId = Tone.Transport.schedule((time) => {
// Check if track should play considering solo logic
const hasSoloedTracks = this.hasSoloedTracks();
if (audioBus.shouldPlayWithSolo(hasSoloedTracks)) {
audioBus.triggerAttackRelease(noteName, noteDuration, time, velocity);
audioBus.triggerAttackRelease(noteName, noteDuration, time + playbackDelay, velocity);
}
}, noteStartTime);
+3 -1
View File
@@ -70,6 +70,7 @@ interface AppConfig {
audio: {
enable_audio_capture_for_screen_sharing: boolean;
lookahead_time: number;
playback_delay: number;
};
templates: {
custom_instructions: string;
@@ -229,7 +230,8 @@ export class ConfigManager {
},
audio: {
enable_audio_capture_for_screen_sharing: false,
lookahead_time: 0.05
lookahead_time: 0.05,
playback_delay: 0.2
},
templates: {
custom_instructions: ''