Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/alphatab/src/synth/AlphaSynth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ export class AlphaSynthBase implements IAlphaSynth {
if (this._countInVolume > 0) {
Logger.debug('AlphaSynth', 'Starting countin');
this.sequencer.startCountIn();
this.synthesizer.setupMetronomeChannel(this._countInVolume);
this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this._countInVolume);
this.updateTimePosition(0, true);
}

Expand All @@ -340,7 +340,7 @@ export class AlphaSynthBase implements IAlphaSynth {
}

Logger.debug('AlphaSynth', 'Starting playback');
this.synthesizer.setupMetronomeChannel(this.metronomeVolume);
this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this.metronomeVolume);
this._synthStopping = false;
this.state = PlayerState.Playing;
(this.stateChanged as EventEmitterOfT<PlayerStateChangedEventArgs>).trigger(
Expand Down Expand Up @@ -442,7 +442,7 @@ export class AlphaSynthBase implements IAlphaSynth {

private _checkReadyForPlayback(): void {
if (this.isReadyForPlayback) {
this.synthesizer.setupMetronomeChannel(this.metronomeVolume);
this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this.metronomeVolume);
const programs = this.sequencer.instrumentPrograms;
const percussionKeys = this.sequencer.percussionKeys;
let append = false;
Expand Down Expand Up @@ -875,7 +875,7 @@ export class AlphaSynthAudioExporter implements IAlphaSynthAudioExporter {
private _generatedAudioEndTime: number = 0;

public setup() {
this._synth.setupMetronomeChannel(this._synth.metronomeVolume);
this._synth.setupMetronomeChannel(this._sequencer.metronomeChannel, this._synth.metronomeVolume);

const syncPoints = this._sequencer.currentSyncPoints;
const alphaTabEndTime = this._sequencer.currentEndTime;
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/src/synth/BackingTrackPlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class BackingTrackAudioSynthesizer implements IAudioSampleSynthesizer {
// not supported, ignore
}

public setupMetronomeChannel(_metronomeVolume: number): void {
public setupMetronomeChannel(_metronomeChannel: number, _metronomeVolume: number): void {
// not supported, ignore
}

Expand Down
3 changes: 2 additions & 1 deletion packages/alphatab/src/synth/IAudioSampleSynthesizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ export interface IAudioSampleSynthesizer {

/**
* Configures the channel used to generate metronome sounds.
* @param metronomeChannel The midi hannel to use for playing the metronome (to avoid overlaps with instruments).
* @param metronomeVolume The volume for the channel.
*/
setupMetronomeChannel(metronomeVolume: number): void;
setupMetronomeChannel(metronomeChannel: number, metronomeVolume: number): void;

/**
* Synthesizes the given number of samples without producing an output (e.g. on seeking)
Expand Down
16 changes: 15 additions & 1 deletion packages/alphatab/src/synth/MidiFileSequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class MidiSequencerState {
public endTime: number = 0;
public currentTempo: number = 0;
public syncPointTempo: number = 0;
public metronomeChannel: number = SynthConstants.DefaultChannelCount - 1;
}

/**
Expand All @@ -65,6 +66,10 @@ export class MidiFileSequencer {
private _oneTimeState: MidiSequencerState | null = null;
private _countInState: MidiSequencerState | null = null;

public get metronomeChannel() {
return this._mainState.metronomeChannel;
}

public get isPlayingMain(): boolean {
return this._currentState === this._mainState;
}
Expand Down Expand Up @@ -171,7 +176,7 @@ export class MidiFileSequencer {
const metronomeVolume: number = this._synthesizer.metronomeVolume;
this._synthesizer.noteOffAll(true);
this._synthesizer.resetSoft();
this._synthesizer.setupMetronomeChannel(metronomeVolume);
this._synthesizer.setupMetronomeChannel(this.metronomeChannel, metronomeVolume);
}
this._mainSilentProcess(timePosition);
}
Expand Down Expand Up @@ -239,6 +244,8 @@ export class MidiFileSequencer {
let metronomeTick: number = midiFile.tickShift; // shift metronome to content
let metronomeTime: number = 0.0;

let maxChannel = 0;

let previousTick: number = 0;
for (const mEvent of midiFile.events) {
const synthData: SynthEvent = new SynthEvent(state.synthData.length, mEvent);
Expand Down Expand Up @@ -287,6 +294,9 @@ export class MidiFileSequencer {
if (!state.firstProgramEventPerChannel.has(channel)) {
state.firstProgramEventPerChannel.set(channel, synthData);
}
if (channel > maxChannel) {
maxChannel = channel;
}
const isPercussion = channel === SynthConstants.PercussionChannel;
if (!isPercussion) {
this.instrumentPrograms.add(programChange.program);
Expand All @@ -297,6 +307,9 @@ export class MidiFileSequencer {
if (isPercussion) {
this.percussionKeys.add(noteOn.noteKey);
}
if (noteOn.channel > maxChannel) {
maxChannel = noteOn.channel;
}
}
}

Expand All @@ -314,6 +327,7 @@ export class MidiFileSequencer {
});
state.endTime = absTime;
state.endTick = absTick;
state.metronomeChannel = maxChannel + 1;

return state;
}
Expand Down
1 change: 0 additions & 1 deletion packages/alphatab/src/synth/SynthConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/
export class SynthConstants {
public static readonly DefaultChannelCount: number = 16 + 1;
public static readonly MetronomeChannel: number = SynthConstants.DefaultChannelCount - 1;
public static readonly MetronomeKey: number = 33;
public static readonly AudioChannels: number = 2;
public static readonly MinVolume: number = 0;
Expand Down
20 changes: 11 additions & 9 deletions packages/alphatab/src/synth/synthesis/TinySoundFont.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class TinySoundFont implements IAudioSampleSynthesizer {
public currentTempo: number = 0;
public timeSignatureNumerator: number = 0;
public timeSignatureDenominator: number = 0;
private _metronomeChannel: number = SynthConstants.DefaultChannelCount - 1;

public constructor(sampleRate: number) {
this.outSampleRate = sampleRate;
Expand Down Expand Up @@ -188,8 +189,8 @@ export class TinySoundFont implements IAudioSampleSynthesizer {
while (!this._midiEventQueue.isEmpty) {
const m: SynthEvent = this._midiEventQueue.dequeue()!;
if (m.isMetronome && this.metronomeVolume > 0) {
this.channelNoteOff(SynthConstants.MetronomeChannel, SynthConstants.MetronomeKey);
this.channelNoteOn(SynthConstants.MetronomeChannel, SynthConstants.MetronomeKey, 95 / 127);
this.channelNoteOff(this._metronomeChannel, SynthConstants.MetronomeKey);
this.channelNoteOn(this._metronomeChannel, SynthConstants.MetronomeKey, 95 / 127);
} else if (m.event) {
this.processMidiMessage(m.event);
}
Expand All @@ -204,7 +205,7 @@ export class TinySoundFont implements IAudioSampleSynthesizer {
// exception. metronome is implicitly added in solo
const isChannelMuted: boolean =
this._mutedChannels.has(channel) ||
(anySolo && channel !== SynthConstants.MetronomeChannel && !this._soloChannels.has(channel));
(anySolo && channel !== this._metronomeChannel && !this._soloChannels.has(channel));

if (!buffer) {
voice.kill();
Expand Down Expand Up @@ -261,18 +262,19 @@ export class TinySoundFont implements IAudioSampleSynthesizer {
}

public get metronomeVolume(): number {
return this.channelGetMixVolume(SynthConstants.MetronomeChannel);
return this.channelGetMixVolume(this._metronomeChannel);
}

public set metronomeVolume(value: number) {
this.setupMetronomeChannel(value);
this.setupMetronomeChannel(this._metronomeChannel, value);
}

public setupMetronomeChannel(volume: number): void {
this.channelSetMixVolume(SynthConstants.MetronomeChannel, volume);
public setupMetronomeChannel(channel:number, volume: number): void {
this._metronomeChannel = channel;
this.channelSetMixVolume(channel, volume);
if (volume > 0) {
this.channelSetVolume(SynthConstants.MetronomeChannel, 1);
this.channelSetPresetNumber(SynthConstants.MetronomeChannel, 0, true);
this.channelSetVolume(channel, 1);
this.channelSetPresetNumber(channel, 0, true);
}
}

Expand Down
9 changes: 7 additions & 2 deletions packages/alphatab/test/audio/SyncPoint.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { type IEventEmitterOfT, type IEventEmitter, EventEmitterOfT, EventEmitter } from '@coderline/alphatab/EventEmitter';
import {
type IEventEmitterOfT,
type IEventEmitter,
EventEmitterOfT,
EventEmitter
} from '@coderline/alphatab/EventEmitter';
import { ScoreLoader } from '@coderline/alphatab/importer/ScoreLoader';
import { AlphaSynthMidiFileHandler } from '@coderline/alphatab/midi/AlphaSynthMidiFileHandler';
import { MidiFile } from '@coderline/alphatab/midi/MidiFile';
Expand Down Expand Up @@ -464,7 +469,7 @@ class EmptyAudioSynthesizer implements IAudioSampleSynthesizer {
_percussionKeys: Set<number>,
_append: boolean
): void {}
public setupMetronomeChannel(_metronomeVolume: number): void {}
public setupMetronomeChannel(_metronomeChannel: number, _metronomeVolume: number): void {}
public synthesizeSilent(_sampleCount: number): void {}
public dispatchEvent(_synthEvent: SynthEvent): void {}
public synthesize(_buffer: Float32Array, _bufferPos: number, _ampleCount: number): SynthEvent[] {
Expand Down
Loading