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();
}