|
| 1 | +import { |
| 2 | + EventEmitter, |
| 3 | + EventEmitterOfT, |
| 4 | + type IEventEmitter, |
| 5 | + type IEventEmitterOfT |
| 6 | +} from '@coderline/alphatab/EventEmitter'; |
| 7 | +import { ByteBuffer } from '@coderline/alphatab/io/ByteBuffer'; |
| 8 | +import { Logger } from '@coderline/alphatab/Logger'; |
| 9 | +import type { LogLevel } from '@coderline/alphatab/LogLevel'; |
| 10 | +import type { MidiEvent, MidiEventType } from '@coderline/alphatab/midi/MidiEvent'; |
1 | 11 | import type { MidiFile } from '@coderline/alphatab/midi/MidiFile'; |
| 12 | +import { MidiUtils } from '@coderline/alphatab/midi/MidiUtils'; |
| 13 | +import { ModelUtils } from '@coderline/alphatab/model/ModelUtils'; |
| 14 | +import type { Score } from '@coderline/alphatab/model/Score'; |
| 15 | +import { Queue } from '@coderline/alphatab/synth/ds/Queue'; |
2 | 16 | import type { BackingTrackSyncPoint, IAlphaSynth } from '@coderline/alphatab/synth/IAlphaSynth'; |
| 17 | +import { |
| 18 | + AudioExportChunk, |
| 19 | + type AudioExportOptions, |
| 20 | + type IAudioExporter |
| 21 | +} from '@coderline/alphatab/synth/IAudioExporter'; |
| 22 | +import type { IAudioSampleSynthesizer } from '@coderline/alphatab/synth/IAudioSampleSynthesizer'; |
3 | 23 | import type { ISynthOutput } from '@coderline/alphatab/synth/ISynthOutput'; |
| 24 | +import { MidiEventsPlayedEventArgs } from '@coderline/alphatab/synth/MidiEventsPlayedEventArgs'; |
4 | 25 | import { MidiFileSequencer } from '@coderline/alphatab/synth/MidiFileSequencer'; |
5 | 26 | import type { PlaybackRange } from '@coderline/alphatab/synth/PlaybackRange'; |
| 27 | +import { PlaybackRangeChangedEventArgs } from '@coderline/alphatab/synth/PlaybackRangeChangedEventArgs'; |
6 | 28 | import { PlayerState } from '@coderline/alphatab/synth/PlayerState'; |
7 | 29 | import { PlayerStateChangedEventArgs } from '@coderline/alphatab/synth/PlayerStateChangedEventArgs'; |
8 | 30 | import { PositionChangedEventArgs } from '@coderline/alphatab/synth/PositionChangedEventArgs'; |
9 | 31 | import { Hydra } from '@coderline/alphatab/synth/soundfont/Hydra'; |
10 | | -import { TinySoundFont } from '@coderline/alphatab/synth/synthesis/TinySoundFont'; |
11 | | -import { EventEmitter, type IEventEmitter, type IEventEmitterOfT, EventEmitterOfT } from '@coderline/alphatab/EventEmitter'; |
12 | | -import { ByteBuffer } from '@coderline/alphatab/io/ByteBuffer'; |
13 | | -import { Logger } from '@coderline/alphatab/Logger'; |
14 | | -import type { LogLevel } from '@coderline/alphatab/LogLevel'; |
15 | 32 | import { SynthConstants } from '@coderline/alphatab/synth/SynthConstants'; |
16 | | -import type { SynthEvent } from '@coderline/alphatab/synth/synthesis/SynthEvent'; |
17 | | -import { Queue } from '@coderline/alphatab/synth/ds/Queue'; |
18 | | -import { MidiEventsPlayedEventArgs } from '@coderline/alphatab/synth/MidiEventsPlayedEventArgs'; |
19 | | -import type { MidiEvent, MidiEventType } from '@coderline/alphatab/midi/MidiEvent'; |
20 | | -import { PlaybackRangeChangedEventArgs } from '@coderline/alphatab/synth/PlaybackRangeChangedEventArgs'; |
21 | | -import { ModelUtils } from '@coderline/alphatab/model/ModelUtils'; |
22 | | -import type { Score } from '@coderline/alphatab/model/Score'; |
23 | | -import type { IAudioSampleSynthesizer } from '@coderline/alphatab/synth/IAudioSampleSynthesizer'; |
24 | | -import { AudioExportChunk, type IAudioExporter, type AudioExportOptions } from '@coderline/alphatab/synth/IAudioExporter'; |
25 | 33 | import type { Preset } from '@coderline/alphatab/synth/synthesis/Preset'; |
26 | | -import { MidiUtils } from '@coderline/alphatab/midi/MidiUtils'; |
| 34 | +import type { SynthEvent } from '@coderline/alphatab/synth/synthesis/SynthEvent'; |
| 35 | +import { TinySoundFont } from '@coderline/alphatab/synth/synthesis/TinySoundFont'; |
27 | 36 |
|
28 | 37 | /** |
29 | 38 | * This is the base class for synthesizer components which can be used to |
@@ -284,6 +293,20 @@ export class AlphaSynthBase implements IAlphaSynth { |
284 | 293 | } |
285 | 294 | this._notPlayedSamples += samples.length; |
286 | 295 | this.output.addSamples(samples); |
| 296 | + |
| 297 | + |
| 298 | + // if the sequencer finished, we instantly force a noteOff on all |
| 299 | + // voices to complete playback and stop voices fast. |
| 300 | + // Doing this in the samplePlayed callback is too late as we might |
| 301 | + // continue generating audio for long-release notes (especially percussion like cymbals) |
| 302 | + |
| 303 | + // we still have checkForFinish which takes care of the counterpart |
| 304 | + // on the sample played area to ensure we seek back. |
| 305 | + // but thanks to this code we ensure the output will complete fast as we won't |
| 306 | + // be adding more samples beside a 0.1s ramp-down |
| 307 | + if (this.sequencer.isFinished) { |
| 308 | + this.synthesizer.noteOffAll(true); |
| 309 | + } |
287 | 310 | } else { |
288 | 311 | // Tell output that there is no data left for it. |
289 | 312 | const samples: Float32Array = new Float32Array(0); |
|
0 commit comments