diff --git a/src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs b/src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs index 7cce0aeaf..50e646d58 100644 --- a/src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs +++ b/src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs @@ -18,7 +18,6 @@ public class NAudioSynthOutput : WaveProvider32, ISynthOutput, IDisposable private DirectSoundOut _context; private CircularSampleBuffer _circularBuffer; - private bool _finished; /// public double SampleRate => PreferredSampleRate; @@ -42,7 +41,6 @@ public void Activate() /// public void Open() { - _finished = false; _circularBuffer = new CircularSampleBuffer(BufferSize * BufferCount); _context = new DirectSoundOut(100); @@ -62,7 +60,6 @@ public void Dispose() /// public void Close() { - _finished = true; _context.Stop(); _circularBuffer.Clear(); _context.Dispose(); @@ -72,7 +69,6 @@ public void Close() public void Play() { RequestBuffers(); - _finished = false; _context.Play(); } @@ -82,12 +78,6 @@ public void Pause() _context.Pause(); } - /// - public void SequencerFinished() - { - _finished = true; - } - /// public void AddSamples(Float32Array f) { @@ -117,29 +107,16 @@ private void RequestBuffers() /// public override int Read(float[] buffer, int offset, int count) { - if (_circularBuffer.Count < count) - { - if (_finished) - { - ((EventEmitter) Finished).Trigger(); - } - } - else - { - var read = new Float32Array(count); - _circularBuffer.Read(read, 0, read.Length); + var read = new Float32Array(count); + _circularBuffer.Read(read, 0, System.Math.Min(read.Length, _circularBuffer.Count)); - Buffer.BlockCopy(read.Data, 0, buffer, offset * sizeof(float), - count * sizeof(float)); + Buffer.BlockCopy(read.Data, 0, buffer, offset * sizeof(float), + count * sizeof(float)); - var samples = count / 2; - ((EventEmitterOfT) SamplesPlayed).Trigger(samples); - } + var samples = count / 2; + ((EventEmitterOfT) SamplesPlayed).Trigger(samples); - if (!_finished) - { - RequestBuffers(); - } + RequestBuffers(); return count; } @@ -152,8 +129,5 @@ public override int Read(float[] buffer, int offset, int count) /// public IEventEmitter SampleRequest { get; } = new EventEmitter(); - - /// - public IEventEmitter Finished { get; } = new EventEmitter(); } } diff --git a/src/platform/javascript/AlphaSynthWebAudioOutput.ts b/src/platform/javascript/AlphaSynthWebAudioOutput.ts index db5dfb8a6..4cc7a15db 100644 --- a/src/platform/javascript/AlphaSynthWebAudioOutput.ts +++ b/src/platform/javascript/AlphaSynthWebAudioOutput.ts @@ -21,14 +21,12 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput { private _source: AudioBufferSourceNode | null = null; private _audioNode: ScriptProcessorNode | null = null; private _circularBuffer!: CircularSampleBuffer; - private _finished: boolean = false; public get sampleRate(): number { return this._context ? this._context.sampleRate : AlphaSynthWebAudioOutput.PreferredSampleRate; } public open(): void { - this._finished = false; this.patchIosSampleRate(); this._circularBuffer = new CircularSampleBuffer( AlphaSynthWebAudioOutput.BufferSize * AlphaSynthWebAudioOutput.BufferCount @@ -75,11 +73,11 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput { context.close(); } } - + private createAudioContext(): AudioContext { - if('AudioContext' in Environment.globalThis) { + if ('AudioContext' in Environment.globalThis) { return new AudioContext(); - } else if('webkitAudioContext' in Environment.globalThis) { + } else if ('webkitAudioContext' in Environment.globalThis) { return new webkitAudioContext(); } throw new AlphaTabError(AlphaTabErrorType.General, "AudioContext not found"); @@ -101,7 +99,6 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput { this._audioNode.onaudioprocess = this.generateSound.bind(this); this._circularBuffer.clear(); this.requestBuffers(); - this._finished = false; this._source = ctx.createBufferSource(); this._source.buffer = this._buffer; this._source.loop = true; @@ -122,10 +119,6 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput { this._audioNode = null; } - public sequencerFinished(): void { - this._finished = true; - } - public addSamples(f: Float32Array): void { this._circularBuffer.write(f, 0, f.length); } @@ -149,27 +142,18 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput { let left: Float32Array = e.outputBuffer.getChannelData(0); let right: Float32Array = e.outputBuffer.getChannelData(1); let samples: number = left.length + right.length; - if (this._circularBuffer.count < samples) { - if (this._finished) { - (this.finished as EventEmitter).trigger(); - } - } else { - let buffer: Float32Array = new Float32Array(samples); - this._circularBuffer.read(buffer, 0, buffer.length); - let s: number = 0; - for (let i: number = 0; i < left.length; i++) { - left[i] = buffer[s++]; - right[i] = buffer[s++]; - } - (this.samplesPlayed as EventEmitterOfT).trigger(left.length); - } - if (!this._finished) { - this.requestBuffers(); + let buffer: Float32Array = new Float32Array(samples); + this._circularBuffer.read(buffer, 0, Math.min(buffer.length, this._circularBuffer.count)); + let s: number = 0; + for (let i: number = 0; i < left.length; i++) { + left[i] = buffer[s++]; + right[i] = buffer[s++]; } + (this.samplesPlayed as EventEmitterOfT).trigger(left.length); + this.requestBuffers(); } readonly ready: IEventEmitter = new EventEmitter(); readonly samplesPlayed: IEventEmitterOfT = new EventEmitterOfT(); readonly sampleRequest: IEventEmitter = new EventEmitter(); - readonly finished: IEventEmitter = new EventEmitter(); } diff --git a/src/platform/javascript/AlphaSynthWebWorkerApi.ts b/src/platform/javascript/AlphaSynthWebWorkerApi.ts index cf9a496b3..9be6af58b 100644 --- a/src/platform/javascript/AlphaSynthWebWorkerApi.ts +++ b/src/platform/javascript/AlphaSynthWebWorkerApi.ts @@ -174,7 +174,6 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth { this._output.ready.on(this.onOutputReady.bind(this)); this._output.samplesPlayed.on(this.onOutputSamplesPlayed.bind(this)); this._output.sampleRequest.on(this.onOutputSampleRequest.bind(this)); - this._output.finished.on(this.onOutputFinished.bind(this)); this._output.open(); try { let script: string = "importScripts('" + alphaSynthScriptFile + "')"; @@ -349,9 +348,6 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth { this.checkReadyForPlayback(); (this.midiLoadFailed as EventEmitterOfT).trigger(data.error); break; - case 'alphaSynth.output.sequencerFinished': - this._output.sequencerFinished(); - break; case 'alphaSynth.output.addSamples': this._output.addSamples(data.samples); break; @@ -400,13 +396,6 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth { cmd: 'alphaSynth.output.sampleRequest' }); } - - public onOutputFinished(): void { - this._synth.postMessage({ - cmd: 'alphaSynth.output.finished' - }); - } - public onOutputSamplesPlayed(samples: number): void { this._synth.postMessage({ cmd: 'alphaSynth.output.samplesPlayed', diff --git a/src/platform/javascript/AlphaSynthWorkerSynthOutput.ts b/src/platform/javascript/AlphaSynthWorkerSynthOutput.ts index de3a45334..19e08b877 100644 --- a/src/platform/javascript/AlphaSynthWorkerSynthOutput.ts +++ b/src/platform/javascript/AlphaSynthWorkerSynthOutput.ts @@ -9,15 +9,12 @@ import { Environment } from '@src/Environment'; */ export class AlphaSynthWorkerSynthOutput implements ISynthOutput { public static readonly CmdOutputPrefix: string = 'alphaSynth.output.'; - public static readonly CmdOutputSequencerFinished: string = - AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'sequencerFinished'; public static readonly CmdOutputAddSamples: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'addSamples'; public static readonly CmdOutputPlay: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'play'; public static readonly CmdOutputPause: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'pause'; public static readonly CmdOutputResetSamples: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'resetSamples'; public static readonly CmdOutputSampleRequest: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'sampleRequest'; - public static readonly CmdOutputFinished: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'finished'; public static readonly CmdOutputSamplesPlayed: string = AlphaSynthWorkerSynthOutput.CmdOutputPrefix + 'samplesPlayed'; @@ -45,9 +42,6 @@ export class AlphaSynthWorkerSynthOutput implements ISynthOutput { case AlphaSynthWorkerSynthOutput.CmdOutputSampleRequest: (this.sampleRequest as EventEmitter).trigger(); break; - case AlphaSynthWorkerSynthOutput.CmdOutputFinished: - (this.finished as EventEmitter).trigger(); - break; case AlphaSynthWorkerSynthOutput.CmdOutputSamplesPlayed: (this.samplesPlayed as EventEmitterOfT).trigger(data.samples); break; @@ -57,13 +51,6 @@ export class AlphaSynthWorkerSynthOutput implements ISynthOutput { public readonly ready: IEventEmitter = new EventEmitter(); public readonly samplesPlayed: IEventEmitterOfT = new EventEmitterOfT(); public readonly sampleRequest: IEventEmitter = new EventEmitter(); - public readonly finished: IEventEmitter = new EventEmitter(); - - public sequencerFinished(): void { - this._worker.postMessage({ - cmd: 'alphaSynth.output.sequencerFinished' - }); - } public addSamples(samples: Float32Array): void { this._worker.postMessage({ diff --git a/src/synth/AlphaSynth.ts b/src/synth/AlphaSynth.ts index aa7e15267..80f4a94f7 100644 --- a/src/synth/AlphaSynth.ts +++ b/src/synth/AlphaSynth.ts @@ -143,30 +143,35 @@ export class AlphaSynth implements IAlphaSynth { (this.ready as EventEmitter).trigger(); this.checkReadyForPlayback(); }); - this.output.finished.on(() => { - // stop everything - this.stop(); - Logger.debug('AlphaSynth', 'Finished playback'); - (this.finished as EventEmitter).trigger(); - if (this._sequencer.isLooping) { - this.play(); - } - }); this.output.sampleRequest.on(() => { - // synthesize buffer - this._sequencer.fillMidiEventQueue(); - let samples: Float32Array = this._synthesizer.synthesize(); + let samples: Float32Array = new Float32Array( + SynthConstants.MicroBufferSize * SynthConstants.MicroBufferCount * SynthConstants.AudioChannels + ); + let bufferPos: number = 0; + + for (let i = 0; i < SynthConstants.MicroBufferCount; i++) { + // synthesize buffer + this._sequencer.fillMidiEventQueue(); + this._synthesizer.synthesize(samples, bufferPos, SynthConstants.MicroBufferSize); + bufferPos += SynthConstants.MicroBufferSize * SynthConstants.AudioChannels; + + // tell sequencer to check whether its work is done + if (this._sequencer.isFinished) { + break; + } + } + // send it to output + if (bufferPos < samples.length) { + samples = samples.subarray(0, bufferPos); + } this.output.addSamples(samples); - // tell sequencer to check whether its work is done - this._sequencer.checkForStop(); }); this.output.samplesPlayed.on(this.onSamplesPlayed.bind(this)); Logger.debug('AlphaSynth', 'Creating synthesizer'); this._synthesizer = new TinySoundFont(this.output.sampleRate); this._sequencer = new MidiFileSequencer(this._synthesizer); - this._sequencer.finished.on(this.output.sequencerFinished.bind(this.output)); Logger.debug('AlphaSynth', 'Opening output'); this.output.open(); @@ -230,7 +235,7 @@ export class AlphaSynth implements IAlphaSynth { (this.soundFontLoaded as EventEmitter).trigger(); } - public loadSoundFont(data: Uint8Array, append:boolean): void { + public loadSoundFont(data: Uint8Array, append: boolean): void { this.pause(); let input: ByteBuffer = ByteBuffer.fromBuffer(data); @@ -299,6 +304,30 @@ export class AlphaSynth implements IAlphaSynth { private onSamplesPlayed(sampleCount: number): void { let playedMillis: number = (sampleCount / this._synthesizer.outSampleRate) * 1000; this.updateTimePosition(this._timePosition + playedMillis); + + this.checkForFinish(); + } + + private checkForFinish() { + let startTick = 0; + let endTick = 0; + if (this.playbackRange) { + startTick = this.playbackRange.startTick; + endTick = this.playbackRange.endTick; + } else { + endTick = this._sequencer.endTick; + } + + if (this._tickPosition >= endTick) { + Logger.debug('AlphaSynth', 'Finished playback'); + (this.finished as EventEmitter).trigger(); + + if (this.isLooping) { + this.tickPosition = startTick; + } else { + this.stop(); + } + } } private updateTimePosition(timePosition: number): void { @@ -309,7 +338,7 @@ export class AlphaSynth implements IAlphaSynth { const endTick: number = this._sequencer.endTick; Logger.debug( 'AlphaSynth', - `Position changed: (time: ${currentTime}/${endTime}, tick: ${currentTick}/${endTime}, Active Voices: ${this._synthesizer.activeVoiceCount}` + `Position changed: (time: ${currentTime}/${endTime}, tick: ${currentTick}/${endTick}, Active Voices: ${this._synthesizer.activeVoiceCount}` ); (this.positionChanged as EventEmitterOfT).trigger( new PositionChangedEventArgs(currentTime, endTime, currentTick, endTick) diff --git a/src/synth/ISynthOutput.ts b/src/synth/ISynthOutput.ts index d0870370c..924884c38 100644 --- a/src/synth/ISynthOutput.ts +++ b/src/synth/ISynthOutput.ts @@ -16,12 +16,6 @@ export interface ISynthOutput { */ open(): void; - /** - * Called when the sequencer finished the playback. - * This tells the output not to request any samples anymore after the existing buffers are finished. - */ - sequencerFinished(): void; - /** * Called when the output should start the playback. */ @@ -62,9 +56,4 @@ export interface ISynthOutput { * Fired when the output needs more samples to be played. */ readonly sampleRequest: IEventEmitter; - - /** - * Fired when the last samples after calling SequencerFinished have been played. - */ - readonly finished: IEventEmitter; } diff --git a/src/synth/MidiFileSequencer.ts b/src/synth/MidiFileSequencer.ts index 8e23c6cc5..b359512f0 100644 --- a/src/synth/MidiFileSequencer.ts +++ b/src/synth/MidiFileSequencer.ts @@ -6,8 +6,8 @@ import { MidiFile } from '@src/midi/MidiFile'; import { PlaybackRange } from '@src/synth/PlaybackRange'; import { SynthEvent } from '@src/synth/synthesis/SynthEvent'; import { TinySoundFont } from '@src/synth/synthesis/TinySoundFont'; -import { EventEmitter, IEventEmitter } from '@src/EventEmitter'; import { Logger } from '@src/Logger'; +import { SynthConstants } from './SynthConstants'; export class MidiFileSequencerTempoChange { public bpm: number; @@ -113,7 +113,7 @@ export class MidiFileSequencer { while (this._currentTime < finalTime) { if (this.fillMidiEventQueueLimited(finalTime - this._currentTime)) { - this._synthesizer.synthesizeSilent(); + this._synthesizer.synthesizeSilent(SynthConstants.MicroBufferSize); } } @@ -196,7 +196,7 @@ export class MidiFileSequencer { private fillMidiEventQueueLimited(maxMilliseconds: number): boolean { let millisecondsPerBuffer: number = - (TinySoundFont.MicroBufferSize / this._synthesizer.outSampleRate) * 1000 * this.playbackSpeed; + (SynthConstants.MicroBufferSize / this._synthesizer.outSampleRate) * 1000 * this.playbackSpeed; let endTime: number = this.internalEndTime; if (maxMilliseconds > 0) { // ensure that first microbuffer does not already exceed max time @@ -207,20 +207,15 @@ export class MidiFileSequencer { } let anyEventsDispatched: boolean = false; - for (let i: number = 0; i < TinySoundFont.MicroBufferCount; i++) { - this._currentTime += millisecondsPerBuffer; - while ( - this._eventIndex < this._synthData.length && - this._synthData[this._eventIndex].time < this._currentTime && - this._currentTime < endTime - ) { - this._synthesizer.dispatchEvent(i, this._synthData[this._eventIndex]); - this._eventIndex++; - anyEventsDispatched = true; - } - if(this._currentTime >= endTime) { - break; - } + this._currentTime += millisecondsPerBuffer; + while ( + this._eventIndex < this._synthData.length && + this._synthData[this._eventIndex].time < this._currentTime && + this._currentTime < endTime + ) { + this._synthesizer.dispatchEvent(this._synthData[this._eventIndex]); + this._eventIndex++; + anyEventsDispatched = true; } return anyEventsDispatched; @@ -281,22 +276,14 @@ export class MidiFileSequencer { return ticks + 1; } - public finished: IEventEmitter = new EventEmitter(); - private get internalEndTime(): number { return !this.playbackRange ? this._endTime : this._playbackRangeEndTime; } - public checkForStop(): void { - if (this._currentTime >= this.internalEndTime) { - let metronomeVolume: number = this._synthesizer.metronomeVolume; - this._synthesizer.noteOffAll(true); - this._synthesizer.resetSoft(); - this._synthesizer.setupMetronomeChannel(metronomeVolume); - (this.finished as EventEmitter).trigger(); - } + public get isFinished(): boolean { + return this._currentTime >= this.internalEndTime; } - + public stop(): void { if (!this.playbackRange) { this._currentTime = 0; diff --git a/src/synth/SynthConstants.ts b/src/synth/SynthConstants.ts index e00bdaf08..786575981 100644 --- a/src/synth/SynthConstants.ts +++ b/src/synth/SynthConstants.ts @@ -26,4 +26,7 @@ export class SynthConstants { * The pitch wheel value for no pitch change at all. */ public static readonly DefaultPitchWheel: number = SynthConstants.MaxPitchWheel / 2; + + public static readonly MicroBufferCount: number = 32; + public static readonly MicroBufferSize: number = 64; } diff --git a/src/synth/synthesis/TinySoundFont.ts b/src/synth/synthesis/TinySoundFont.ts index d7b33ee6a..aa1f2fb19 100644 --- a/src/synth/synthesis/TinySoundFont.ts +++ b/src/synth/synthesis/TinySoundFont.ts @@ -36,11 +36,8 @@ import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; * - Support for modulators */ export class TinySoundFont { - public static readonly MicroBufferCount: number = 32; // 4069 samples in total - public static readonly MicroBufferSize: number = 64; // 64 stereo samples - private _midiEventQueue: SynthEvent[] = []; - private _midiEventCounts: Int32Array = new Int32Array(TinySoundFont.MicroBufferCount); + private _midiEventCount: number = 0; private _mutedChannels: Map = new Map(); private _soloChannels: Map = new Map(); private _isAnySolo: boolean = false; @@ -49,12 +46,12 @@ export class TinySoundFont { this.outSampleRate = sampleRate; } - public synthesize(): Float32Array { - return this.fillWorkingBuffer(false); + public synthesize(buffer: Float32Array, bufferPos: number, sampleCount: number) { + this.fillWorkingBuffer(buffer, bufferPos, sampleCount); } - public synthesizeSilent(): void { - this.fillWorkingBuffer(true); + public synthesizeSilent(sampleCount: number): void { + this.fillWorkingBuffer(null, 0, sampleCount); } public channelGetMixVolume(channel: number): number { @@ -96,57 +93,49 @@ export class TinySoundFont { this._isAnySolo = false; } - public dispatchEvent(i: number, synthEvent: SynthEvent): void { + public dispatchEvent(synthEvent: SynthEvent): void { this._midiEventQueue.unshift(synthEvent); - this._midiEventCounts[i]++; + this._midiEventCount++; } - private fillWorkingBuffer(silent: boolean): Float32Array { + private fillWorkingBuffer(buffer: Float32Array | null, bufferPos: number, sampleCount: number) { // Break the process loop into sections representing the smallest timeframe before the midi controls need to be updated // the bigger the timeframe the more efficent the process is, but playback quality will be reduced. - const buffer: Float32Array = new Float32Array( - TinySoundFont.MicroBufferSize * TinySoundFont.MicroBufferCount * SynthConstants.AudioChannels - ); - let bufferPos: number = 0; const anySolo: boolean = this._isAnySolo; // process in micro-buffers - for (let x: number = 0; x < TinySoundFont.MicroBufferCount; x++) { - // process events for first microbuffer - if (this._midiEventQueue.length > 0) { - for (let i: number = 0; i < this._midiEventCounts[x]; i++) { - let m: SynthEvent | undefined = this._midiEventQueue.pop(); - if (m) { - if (m.isMetronome && this.metronomeVolume > 0) { - this.channelNoteOff(SynthConstants.MetronomeChannel, 33); - this.channelNoteOn(SynthConstants.MetronomeChannel, 33, 95 / 127); - } else if (m.event) { - this.processMidiMessage(m.event); - } + // process events for first microbuffer + if (this._midiEventQueue.length > 0) { + for (let i: number = 0; i < this._midiEventCount; i++) { + let m: SynthEvent | undefined = this._midiEventQueue.pop(); + if (m) { + if (m.isMetronome && this.metronomeVolume > 0) { + this.channelNoteOff(SynthConstants.MetronomeChannel, 33); + this.channelNoteOn(SynthConstants.MetronomeChannel, 33, 95 / 127); + } else if (m.event) { + this.processMidiMessage(m.event); } } } + } - // voice processing loop - for (const voice of this._voices) { - if (voice.playingPreset !== -1) { - const channel: number = voice.playingChannel; - // channel is muted if it is either explicitley muted, or another channel is set to solo but not this one. - const isChannelMuted: boolean = - this._mutedChannels.has(channel) || (anySolo && !this._soloChannels.has(channel)); - - if (silent) { - voice.kill(); - } else { - voice.render(this, buffer, bufferPos, 64, isChannelMuted); - } + // voice processing loop + for (const voice of this._voices) { + if (voice.playingPreset !== -1) { + const channel: number = voice.playingChannel; + // channel is muted if it is either explicitley muted, or another channel is set to solo but not this one. + const isChannelMuted: boolean = + this._mutedChannels.has(channel) || (anySolo && !this._soloChannels.has(channel)); + + if (!buffer) { + voice.kill(); + } else { + voice.render(this, buffer, bufferPos, sampleCount, isChannelMuted); } } - bufferPos += TinySoundFont.MicroBufferSize * SynthConstants.AudioChannels; } - this._midiEventCounts.fill(0); - return buffer; + this._midiEventCount = 0; } private processMidiMessage(e: MidiEvent): void { diff --git a/src/synth/synthesis/Voice.ts b/src/synth/synthesis/Voice.ts index e49048f28..cf6bdd401 100644 --- a/src/synth/synthesis/Voice.ts +++ b/src/synth/synthesis/Voice.ts @@ -10,6 +10,7 @@ import { VoiceEnvelope, VoiceEnvelopeSegment } from '@src/synth/synthesis/VoiceE import { VoiceLfo } from '@src/synth/synthesis/VoiceLfo'; import { VoiceLowPass } from '@src/synth/synthesis/VoiceLowPass'; import { SynthHelper } from '@src/synth/SynthHelper'; +import { SynthConstants } from '../SynthConstants'; import { Channel } from './Channel'; export class Voice { @@ -18,7 +19,7 @@ export class Voice { * Increasing the value significantly lowers the CPU usage of the voice rendering. * If LFO affects the low-pass filter it can be hearable even as low as 8. */ - private static readonly RenderEffectSampleBLock: number = 64; + private static readonly RenderEffectSampleBlock: number = SynthConstants.MicroBufferSize; public playingPreset: number = 0; public playingKey: number = 0; @@ -180,7 +181,7 @@ export class Voice { let gainMono: number; let gainLeft: number; let gainRight: number = 0; - let blockSamples: number = numSamples > Voice.RenderEffectSampleBLock ? Voice.RenderEffectSampleBLock : numSamples; + let blockSamples: number = numSamples > Voice.RenderEffectSampleBlock ? Voice.RenderEffectSampleBlock : numSamples; numSamples -= blockSamples; if (dynamicLowpass) { diff --git a/test/audio/TestOutput.ts b/test/audio/TestOutput.ts index ae95311d5..c48d9830a 100644 --- a/test/audio/TestOutput.ts +++ b/test/audio/TestOutput.ts @@ -2,7 +2,6 @@ import { ISynthOutput } from '@src/synth/ISynthOutput'; import { EventEmitter, IEventEmitter, IEventEmitterOfT, EventEmitterOfT } from '@src/EventEmitter'; export class TestOutput implements ISynthOutput { - private _finished: boolean = false; public samples: number[] = []; public get sampleRate(): number { @@ -14,20 +13,12 @@ export class TestOutput implements ISynthOutput { (this.ready as EventEmitter).trigger(); } - public sequencerFinished(): void { - this._finished = true; - } - public play(): void { // nothing to do } public next(): void { - if (this._finished) { - (this.finished as EventEmitter).trigger(); - } else { - (this.sampleRequest as EventEmitter).trigger(); - } + (this.sampleRequest as EventEmitter).trigger(); } public pause(): void { @@ -63,9 +54,4 @@ export class TestOutput implements ISynthOutput { * Fired when the output needs more samples to be played. */ readonly sampleRequest: IEventEmitter = new EventEmitter(); - - /** - * Fired when the last samples after calling SequencerFinished have been played. - */ - readonly finished: IEventEmitter = new EventEmitter(); }