diff --git a/src/audio/piano-sampler.ts b/src/audio/piano-sampler.ts index 5e0b771..8c27e33 100644 --- a/src/audio/piano-sampler.ts +++ b/src/audio/piano-sampler.ts @@ -8,7 +8,7 @@ import type { LoadedPianoStrikeSample, PianoNote, } from './garden-audio-types'; -import { getLoadedPianoSamples, loadPianoSamples } from './piano-samples'; +import { ensurePianoSamplesLoading, subscribeToPianoSamples } from './piano-samples'; export const PIANO_SCHEDULE_AHEAD_SECONDS = 0.002; @@ -52,6 +52,7 @@ export class PianoSampler { private releaseSamples: Array = []; private strikeSamples: Array = []; private velocityLayers: Array = []; + private unsubscribeFromSampleUpdates: (() => void) | null = null; public constructor( private readonly config: GardenAudioConfig, @@ -59,19 +60,17 @@ export class PianoSampler { ) {} public load(context: BaseAudioContext): Promise { + // The subscription applies further velocity layers and release samples + // as they finish loading in the background. + this.unsubscribeFromSampleUpdates ??= subscribeToPianoSamples((samples) => { + this.setSamples(samples); + }); + if (this.strikeSamples.length > 0) { return Promise.resolve(); } - const loadedSamples = getLoadedPianoSamples(); - if (loadedSamples) { - this.setSamples(loadedSamples); - return Promise.resolve(); - } - - return loadPianoSamples(context).then((samples) => { - this.setSamples(samples); - }); + return ensurePianoSamplesLoading(context); } public play({ @@ -161,6 +160,8 @@ export class PianoSampler { } public reset(): void { + this.unsubscribeFromSampleUpdates?.(); + this.unsubscribeFromSampleUpdates = null; this.releaseSamples = []; this.strikeSamples = []; this.velocityLayers = []; diff --git a/src/audio/piano-samples.ts b/src/audio/piano-samples.ts index 2d2bc25..560ed67 100644 --- a/src/audio/piano-samples.ts +++ b/src/audio/piano-samples.ts @@ -1,3 +1,4 @@ +import { ErrorHandler, Severity } from '../utils/error-handler'; import type { LoadedPianoReleaseSample, LoadedPianoSamples, @@ -21,6 +22,8 @@ interface PianoReleaseSampleDefinition { type PianoSampleDefinition = PianoStrikeSampleDefinition | PianoReleaseSampleDefinition; +type LoadedPianoSample = LoadedPianoStrikeSample | LoadedPianoReleaseSample; + export interface PianoSampleLoadProgress { failedCount: number; loadedCount: number; @@ -35,8 +38,24 @@ const pianoSampleModules = import.meta.glob('./samples/*.m4a', { }) as Record; const pianoSampleDefinitions = getPianoSampleDefinitions(pianoSampleModules); -let loadedPianoSamples: LoadedPianoSamples | null = null; -let pianoSampleLoadPromise: Promise | null = null; +// The sampler degrades gracefully on a partial set: it picks the nearest +// available strike per note, blends whatever velocity layers exist, and +// treats release samples as optional. The core velocity layer is therefore +// enough to start playing; the remaining layers and the release samples +// stream in afterwards, published per completed layer so nearest-sample +// lookups never see a half-loaded layer. +const coreVelocityLayer = 8; +const corePianoSampleDefinitions = pianoSampleDefinitions.filter( + (definition) => + definition.kind === 'strike' && definition.velocityLayer === coreVelocityLayer +); +const backgroundPianoSamplePhases = getBackgroundPianoSamplePhases(); + +const loadedSamplesByPath = new Map(); +let publishedSamples: LoadedPianoSamples | null = null; +let coreSampleLoadPromise: Promise | null = null; +let isLoadingBackgroundSamples = false; +const sampleSubscribers = new Set<(samples: LoadedPianoSamples) => void>(); let lastPianoSampleProgress: PianoSampleLoadProgress | null = null; const pianoSampleProgressListeners = new Set< (progress: PianoSampleLoadProgress) => void @@ -49,7 +68,7 @@ const sampleLoadTuning = { export const preloadPianoSamples = ( onProgress?: (progress: PianoSampleLoadProgress) => void -): Promise => { +): Promise => { const OfflineAudioContextConstructor = globalThis.OfflineAudioContext; if (!OfflineAudioContextConstructor) { @@ -60,87 +79,133 @@ export const preloadPianoSamples = ( // Decoding ignores these, but the constructor demands real numbers. const decodeContext = new OfflineAudioContextConstructor(1, 1, 48_000); - return loadPianoSamples(decodeContext, onProgress); + return ensurePianoSamplesLoading(decodeContext, onProgress); }; -export const loadPianoSamples = ( +/** + * Starts loading samples if needed and resolves once the core velocity layer + * is playable. Failed samples are retried on the next call; background layers + * keep streaming in after resolution. + */ +export const ensurePianoSamplesLoading = ( decodeContext: BaseAudioContext, onProgress?: (progress: PianoSampleLoadProgress) => void -): Promise => { +): Promise => { const unsubscribeProgress = subscribeToPianoSampleProgress(onProgress); - if (loadedPianoSamples) { - emitPianoSampleProgress({ - failedCount: 0, - loadedCount: loadedPianoSamples.strikes.length + loadedPianoSamples.releases.length, - settledCount: - loadedPianoSamples.strikes.length + loadedPianoSamples.releases.length, - totalCount: pianoSampleDefinitions.length, - }); - unsubscribeProgress(); - return Promise.resolve(cloneLoadedPianoSamples(loadedPianoSamples)); - } + coreSampleLoadPromise ??= loadCoreSamples(decodeContext).catch((error: unknown) => { + coreSampleLoadPromise = null; + throw error; + }); + coreSampleLoadPromise.then( + () => { + startBackgroundLoading(decodeContext); + }, + () => undefined + ); - if (pianoSampleLoadPromise) { - return pianoSampleLoadPromise.finally(unsubscribeProgress); - } - - let loadedCount = 0; - let failedCount = 0; - let settledCount = 0; - const totalCount = pianoSampleDefinitions.length; - emitPianoSampleProgress({ failedCount, loadedCount, settledCount, totalCount }); - - pianoSampleLoadPromise = loadPianoSampleBatch( - pianoSampleDefinitions, - async (sample) => { - try { - const loadedSample = await withTimeout( - (signal) => loadPianoSample(decodeContext, sample, signal), - sampleLoadTuning.sampleTimeoutMs - ); - loadedCount += 1; - return loadedSample; - } catch (error) { - failedCount += 1; - throw error; - } finally { - settledCount += 1; - emitPianoSampleProgress({ failedCount, loadedCount, settledCount, totalCount }); - } - } - ) - .then( - (samples) => { - loadedPianoSamples = sortLoadedPianoSamples(samples); - const loadedCount = - loadedPianoSamples.strikes.length + loadedPianoSamples.releases.length; - if (loadedCount !== pianoSampleDefinitions.length) { - throw new Error( - `Loaded ${loadedCount}/${pianoSampleDefinitions.length} piano samples.` - ); - } - return cloneLoadedPianoSamples(loadedPianoSamples); - }, - (error: unknown) => { - pianoSampleLoadPromise = null; - pianoSampleProgressListeners.clear(); - throw error; - } - ) - .finally(unsubscribeProgress); - - return pianoSampleLoadPromise; + return coreSampleLoadPromise.finally(unsubscribeProgress); }; -export const getLoadedPianoSamples = (): LoadedPianoSamples | null => - loadedPianoSamples ? cloneLoadedPianoSamples(loadedPianoSamples) : null; +/** + * Calls the listener with the currently published samples (if any) and again + * whenever another batch finishes loading. Returns an unsubscribe function. + */ +export const subscribeToPianoSamples = ( + listener: (samples: LoadedPianoSamples) => void +): (() => void) => { + sampleSubscribers.add(listener); + if (publishedSamples) { + listener(cloneLoadedPianoSamples(publishedSamples)); + } + return () => { + sampleSubscribers.delete(listener); + }; +}; + +const loadCoreSamples = async (decodeContext: BaseAudioContext): Promise => { + const pending = corePianoSampleDefinitions.filter( + (definition) => !loadedSamplesByPath.has(definition.path) + ); + const totalCount = corePianoSampleDefinitions.length; + let loadedCount = totalCount - pending.length; + let settledCount = loadedCount; + let failedCount = 0; + emitPianoSampleProgress({ failedCount, loadedCount, settledCount, totalCount }); + + await loadSamplesWithConcurrency(pending, async (definition) => { + try { + await loadPianoSample(decodeContext, definition); + loadedCount += 1; + } catch (error) { + failedCount += 1; + throw error; + } finally { + settledCount += 1; + emitPianoSampleProgress({ failedCount, loadedCount, settledCount, totalCount }); + } + }); + + publishLoadedSamples(); +}; + +const startBackgroundLoading = (decodeContext: BaseAudioContext): void => { + if ( + isLoadingBackgroundSamples || + loadedSamplesByPath.size === pianoSampleDefinitions.length + ) { + return; + } + + isLoadingBackgroundSamples = true; + loadBackgroundSamples(decodeContext).then( + () => { + isLoadingBackgroundSamples = false; + }, + (error: unknown) => { + // The piano stays playable on the samples loaded so far; the next + // ensurePianoSamplesLoading call retries whatever is still missing. + isLoadingBackgroundSamples = false; + ErrorHandler.addException(error, { + fallbackMessage: 'Could not load all piano samples.', + severity: Severity.WARNING, + }); + } + ); +}; + +const loadBackgroundSamples = async (decodeContext: BaseAudioContext): Promise => { + for (const phaseDefinitions of backgroundPianoSamplePhases) { + const pending = phaseDefinitions.filter( + (definition) => !loadedSamplesByPath.has(definition.path) + ); + if (pending.length === 0) { + continue; + } + + await loadSamplesWithConcurrency(pending, (definition) => + loadPianoSample(decodeContext, definition) + ); + publishLoadedSamples(); + } +}; const loadPianoSample = async ( + decodeContext: BaseAudioContext, + sample: PianoSampleDefinition +): Promise => { + const loadedSample = await withTimeout( + (signal) => fetchAndDecodePianoSample(decodeContext, sample, signal), + sampleLoadTuning.sampleTimeoutMs + ); + loadedSamplesByPath.set(sample.path, loadedSample); +}; + +const fetchAndDecodePianoSample = async ( decodeContext: BaseAudioContext, sample: PianoSampleDefinition, signal: AbortSignal -): Promise => { +): Promise => { const response = await fetch(sample.url, { signal }); if (!response.ok) { throw new Error(`Unable to load piano sample ${sample.path}`); @@ -158,21 +223,34 @@ const loadPianoSample = async ( return { buffer, midi: sample.midi }; }; -const loadPianoSampleBatch = async ( +/** + * Runs the loads through a sliding window of workers so one slow sample only + * occupies a single slot instead of stalling a whole batch. + */ +const loadSamplesWithConcurrency = async ( samples: Array, - loadSample: ( - sample: PianoSampleDefinition - ) => Promise -): Promise> => { - const results: Array = []; + loadSample: (sample: PianoSampleDefinition) => Promise +): Promise => { + let nextIndex = 0; + const workerCount = Math.min(sampleLoadTuning.concurrency, samples.length); - for (let index = 0; index < samples.length; index += sampleLoadTuning.concurrency) { - const batch = samples.slice(index, index + sampleLoadTuning.concurrency); - const batchResults = await Promise.all(batch.map((sample) => loadSample(sample))); - results.push(...batchResults); - } + await Promise.all( + Array.from({ length: workerCount }, async () => { + while (nextIndex < samples.length) { + const sample = samples[nextIndex]; + nextIndex += 1; + await loadSample(sample); + } + }) + ); +}; - return results; +const publishLoadedSamples = (): void => { + const samples = sortLoadedPianoSamples([...loadedSamplesByPath.values()]); + publishedSamples = samples; + sampleSubscribers.forEach((listener) => { + listener(cloneLoadedPianoSamples(samples)); + }); }; const withTimeout = ( @@ -219,6 +297,29 @@ const emitPianoSampleProgress = (progress: PianoSampleLoadProgress): void => { pianoSampleProgressListeners.forEach((listener) => listener(progress)); }; +function getBackgroundPianoSamplePhases(): Array> { + const strikes = pianoSampleDefinitions.filter( + (definition) => definition.kind === 'strike' + ); + const releases = pianoSampleDefinitions.filter( + (definition) => definition.kind === 'release' + ); + // Layers closest to the core layer first: they are blended in soonest by + // getVelocityLayerPair; ties resolve to the louder layer. + const remainingLayers = [...new Set(strikes.map((strike) => strike.velocityLayer))] + .filter((layer) => layer !== coreVelocityLayer) + .sort( + (a, b) => Math.abs(a - coreVelocityLayer) - Math.abs(b - coreVelocityLayer) || b - a + ); + + return [ + releases, + ...remainingLayers.map((layer) => + strikes.filter((strike) => strike.velocityLayer === layer) + ), + ]; +} + function getPianoSampleDefinitions( modules: Record ): Array { @@ -285,7 +386,7 @@ function getMidiForReleaseSample(releaseIndex: number): number { } const sortLoadedPianoSamples = ( - samples: Array + samples: Array ): LoadedPianoSamples => ({ releases: samples .filter((sample): sample is LoadedPianoReleaseSample => !('velocityLayer' in sample)) diff --git a/src/audio/samples/A0v12.m4a b/src/audio/samples/A0v12.m4a index 71c0564..c733dcd 100644 Binary files a/src/audio/samples/A0v12.m4a and b/src/audio/samples/A0v12.m4a differ diff --git a/src/audio/samples/A0v16.m4a b/src/audio/samples/A0v16.m4a index aae9230..78e1d90 100644 Binary files a/src/audio/samples/A0v16.m4a and b/src/audio/samples/A0v16.m4a differ diff --git a/src/audio/samples/A0v4.m4a b/src/audio/samples/A0v4.m4a index 0679ac0..a28725d 100644 Binary files a/src/audio/samples/A0v4.m4a and b/src/audio/samples/A0v4.m4a differ diff --git a/src/audio/samples/A0v8.m4a b/src/audio/samples/A0v8.m4a index 99195dd..e2825c1 100644 Binary files a/src/audio/samples/A0v8.m4a and b/src/audio/samples/A0v8.m4a differ diff --git a/src/audio/samples/A1v12.m4a b/src/audio/samples/A1v12.m4a index 4d47370..e6647b9 100644 Binary files a/src/audio/samples/A1v12.m4a and b/src/audio/samples/A1v12.m4a differ diff --git a/src/audio/samples/A1v16.m4a b/src/audio/samples/A1v16.m4a index a85872d..d417db4 100644 Binary files a/src/audio/samples/A1v16.m4a and b/src/audio/samples/A1v16.m4a differ diff --git a/src/audio/samples/A1v4.m4a b/src/audio/samples/A1v4.m4a index 8095af9..21d91f2 100644 Binary files a/src/audio/samples/A1v4.m4a and b/src/audio/samples/A1v4.m4a differ diff --git a/src/audio/samples/A1v8.m4a b/src/audio/samples/A1v8.m4a index de6d334..e4067ef 100644 Binary files a/src/audio/samples/A1v8.m4a and b/src/audio/samples/A1v8.m4a differ diff --git a/src/audio/samples/A2v12.m4a b/src/audio/samples/A2v12.m4a index 2ac10d3..c16b3a3 100644 Binary files a/src/audio/samples/A2v12.m4a and b/src/audio/samples/A2v12.m4a differ diff --git a/src/audio/samples/A2v16.m4a b/src/audio/samples/A2v16.m4a index 8aa478c..f4cd1db 100644 Binary files a/src/audio/samples/A2v16.m4a and b/src/audio/samples/A2v16.m4a differ diff --git a/src/audio/samples/A2v4.m4a b/src/audio/samples/A2v4.m4a index f241c2e..43eb37c 100644 Binary files a/src/audio/samples/A2v4.m4a and b/src/audio/samples/A2v4.m4a differ diff --git a/src/audio/samples/A2v8.m4a b/src/audio/samples/A2v8.m4a index ceaca7f..963c496 100644 Binary files a/src/audio/samples/A2v8.m4a and b/src/audio/samples/A2v8.m4a differ diff --git a/src/audio/samples/A3v12.m4a b/src/audio/samples/A3v12.m4a index 10cc72c..d0ae013 100644 Binary files a/src/audio/samples/A3v12.m4a and b/src/audio/samples/A3v12.m4a differ diff --git a/src/audio/samples/A3v16.m4a b/src/audio/samples/A3v16.m4a index a100c90..987d2b6 100644 Binary files a/src/audio/samples/A3v16.m4a and b/src/audio/samples/A3v16.m4a differ diff --git a/src/audio/samples/A3v4.m4a b/src/audio/samples/A3v4.m4a index 0eae496..ea30e35 100644 Binary files a/src/audio/samples/A3v4.m4a and b/src/audio/samples/A3v4.m4a differ diff --git a/src/audio/samples/A3v8.m4a b/src/audio/samples/A3v8.m4a index 2158608..25cc90b 100644 Binary files a/src/audio/samples/A3v8.m4a and b/src/audio/samples/A3v8.m4a differ diff --git a/src/audio/samples/A4v12.m4a b/src/audio/samples/A4v12.m4a index 7fe52f4..8815c27 100644 Binary files a/src/audio/samples/A4v12.m4a and b/src/audio/samples/A4v12.m4a differ diff --git a/src/audio/samples/A4v16.m4a b/src/audio/samples/A4v16.m4a index 4d20781..b2477ab 100644 Binary files a/src/audio/samples/A4v16.m4a and b/src/audio/samples/A4v16.m4a differ diff --git a/src/audio/samples/A4v4.m4a b/src/audio/samples/A4v4.m4a index 4e55c94..eb74c3b 100644 Binary files a/src/audio/samples/A4v4.m4a and b/src/audio/samples/A4v4.m4a differ diff --git a/src/audio/samples/A4v8.m4a b/src/audio/samples/A4v8.m4a index 335fa93..ca065e4 100644 Binary files a/src/audio/samples/A4v8.m4a and b/src/audio/samples/A4v8.m4a differ diff --git a/src/audio/samples/A5v12.m4a b/src/audio/samples/A5v12.m4a index 9d3d280..13b02e1 100644 Binary files a/src/audio/samples/A5v12.m4a and b/src/audio/samples/A5v12.m4a differ diff --git a/src/audio/samples/A5v16.m4a b/src/audio/samples/A5v16.m4a index cd7c62f..8fc549d 100644 Binary files a/src/audio/samples/A5v16.m4a and b/src/audio/samples/A5v16.m4a differ diff --git a/src/audio/samples/A5v4.m4a b/src/audio/samples/A5v4.m4a index c68176e..cc9e540 100644 Binary files a/src/audio/samples/A5v4.m4a and b/src/audio/samples/A5v4.m4a differ diff --git a/src/audio/samples/A5v8.m4a b/src/audio/samples/A5v8.m4a index 0afb0b9..23bed94 100644 Binary files a/src/audio/samples/A5v8.m4a and b/src/audio/samples/A5v8.m4a differ diff --git a/src/audio/samples/A6v12.m4a b/src/audio/samples/A6v12.m4a index 9b8644d..ac46371 100644 Binary files a/src/audio/samples/A6v12.m4a and b/src/audio/samples/A6v12.m4a differ diff --git a/src/audio/samples/A6v16.m4a b/src/audio/samples/A6v16.m4a index 26bcc55..3b1a140 100644 Binary files a/src/audio/samples/A6v16.m4a and b/src/audio/samples/A6v16.m4a differ diff --git a/src/audio/samples/A6v4.m4a b/src/audio/samples/A6v4.m4a index 6d37b98..ea0d0e6 100644 Binary files a/src/audio/samples/A6v4.m4a and b/src/audio/samples/A6v4.m4a differ diff --git a/src/audio/samples/A6v8.m4a b/src/audio/samples/A6v8.m4a index bd89797..0b1b4c8 100644 Binary files a/src/audio/samples/A6v8.m4a and b/src/audio/samples/A6v8.m4a differ diff --git a/src/audio/samples/A7v12.m4a b/src/audio/samples/A7v12.m4a index 2a4193b..1f66482 100644 Binary files a/src/audio/samples/A7v12.m4a and b/src/audio/samples/A7v12.m4a differ diff --git a/src/audio/samples/A7v16.m4a b/src/audio/samples/A7v16.m4a index c0f0e52..737a5c9 100644 Binary files a/src/audio/samples/A7v16.m4a and b/src/audio/samples/A7v16.m4a differ diff --git a/src/audio/samples/A7v4.m4a b/src/audio/samples/A7v4.m4a index 2106892..974e91e 100644 Binary files a/src/audio/samples/A7v4.m4a and b/src/audio/samples/A7v4.m4a differ diff --git a/src/audio/samples/A7v8.m4a b/src/audio/samples/A7v8.m4a index a25a530..e380911 100644 Binary files a/src/audio/samples/A7v8.m4a and b/src/audio/samples/A7v8.m4a differ diff --git a/src/audio/samples/C1v12.m4a b/src/audio/samples/C1v12.m4a index d94fd2e..c147d3a 100644 Binary files a/src/audio/samples/C1v12.m4a and b/src/audio/samples/C1v12.m4a differ diff --git a/src/audio/samples/C1v16.m4a b/src/audio/samples/C1v16.m4a index f6c995d..26e48e8 100644 Binary files a/src/audio/samples/C1v16.m4a and b/src/audio/samples/C1v16.m4a differ diff --git a/src/audio/samples/C1v4.m4a b/src/audio/samples/C1v4.m4a index 5c2d043..842adf1 100644 Binary files a/src/audio/samples/C1v4.m4a and b/src/audio/samples/C1v4.m4a differ diff --git a/src/audio/samples/C1v8.m4a b/src/audio/samples/C1v8.m4a index febaf24..8fffad8 100644 Binary files a/src/audio/samples/C1v8.m4a and b/src/audio/samples/C1v8.m4a differ diff --git a/src/audio/samples/C2v12.m4a b/src/audio/samples/C2v12.m4a index 44bda1a..ba32f35 100644 Binary files a/src/audio/samples/C2v12.m4a and b/src/audio/samples/C2v12.m4a differ diff --git a/src/audio/samples/C2v16.m4a b/src/audio/samples/C2v16.m4a index bb729d8..664c985 100644 Binary files a/src/audio/samples/C2v16.m4a and b/src/audio/samples/C2v16.m4a differ diff --git a/src/audio/samples/C2v4.m4a b/src/audio/samples/C2v4.m4a index 9ce27c9..07932a9 100644 Binary files a/src/audio/samples/C2v4.m4a and b/src/audio/samples/C2v4.m4a differ diff --git a/src/audio/samples/C2v8.m4a b/src/audio/samples/C2v8.m4a index 3cd4b1c..36d87d3 100644 Binary files a/src/audio/samples/C2v8.m4a and b/src/audio/samples/C2v8.m4a differ diff --git a/src/audio/samples/C3v12.m4a b/src/audio/samples/C3v12.m4a index a7c9af0..079efeb 100644 Binary files a/src/audio/samples/C3v12.m4a and b/src/audio/samples/C3v12.m4a differ diff --git a/src/audio/samples/C3v16.m4a b/src/audio/samples/C3v16.m4a index d6ad787..af99f33 100644 Binary files a/src/audio/samples/C3v16.m4a and b/src/audio/samples/C3v16.m4a differ diff --git a/src/audio/samples/C3v4.m4a b/src/audio/samples/C3v4.m4a index e850712..f2c2ac8 100644 Binary files a/src/audio/samples/C3v4.m4a and b/src/audio/samples/C3v4.m4a differ diff --git a/src/audio/samples/C3v8.m4a b/src/audio/samples/C3v8.m4a index e781b6b..616a5da 100644 Binary files a/src/audio/samples/C3v8.m4a and b/src/audio/samples/C3v8.m4a differ diff --git a/src/audio/samples/C4v12.m4a b/src/audio/samples/C4v12.m4a index fb37963..df63a28 100644 Binary files a/src/audio/samples/C4v12.m4a and b/src/audio/samples/C4v12.m4a differ diff --git a/src/audio/samples/C4v16.m4a b/src/audio/samples/C4v16.m4a index eed90fa..bd1d761 100644 Binary files a/src/audio/samples/C4v16.m4a and b/src/audio/samples/C4v16.m4a differ diff --git a/src/audio/samples/C4v4.m4a b/src/audio/samples/C4v4.m4a index 7f1994f..073958e 100644 Binary files a/src/audio/samples/C4v4.m4a and b/src/audio/samples/C4v4.m4a differ diff --git a/src/audio/samples/C4v8.m4a b/src/audio/samples/C4v8.m4a index 9a45ff8..501e2aa 100644 Binary files a/src/audio/samples/C4v8.m4a and b/src/audio/samples/C4v8.m4a differ diff --git a/src/audio/samples/C5v12.m4a b/src/audio/samples/C5v12.m4a index 3c08107..f67436d 100644 Binary files a/src/audio/samples/C5v12.m4a and b/src/audio/samples/C5v12.m4a differ diff --git a/src/audio/samples/C5v16.m4a b/src/audio/samples/C5v16.m4a index 24edb5a..cbc307c 100644 Binary files a/src/audio/samples/C5v16.m4a and b/src/audio/samples/C5v16.m4a differ diff --git a/src/audio/samples/C5v4.m4a b/src/audio/samples/C5v4.m4a index 130ea2e..bb18ba7 100644 Binary files a/src/audio/samples/C5v4.m4a and b/src/audio/samples/C5v4.m4a differ diff --git a/src/audio/samples/C5v8.m4a b/src/audio/samples/C5v8.m4a index 403b22d..fd700ed 100644 Binary files a/src/audio/samples/C5v8.m4a and b/src/audio/samples/C5v8.m4a differ diff --git a/src/audio/samples/C6v12.m4a b/src/audio/samples/C6v12.m4a index d8268ff..2e89c33 100644 Binary files a/src/audio/samples/C6v12.m4a and b/src/audio/samples/C6v12.m4a differ diff --git a/src/audio/samples/C6v16.m4a b/src/audio/samples/C6v16.m4a index 8305844..3e284aa 100644 Binary files a/src/audio/samples/C6v16.m4a and b/src/audio/samples/C6v16.m4a differ diff --git a/src/audio/samples/C6v4.m4a b/src/audio/samples/C6v4.m4a index 8646b5b..f810164 100644 Binary files a/src/audio/samples/C6v4.m4a and b/src/audio/samples/C6v4.m4a differ diff --git a/src/audio/samples/C6v8.m4a b/src/audio/samples/C6v8.m4a index f85e6a1..78a6b7f 100644 Binary files a/src/audio/samples/C6v8.m4a and b/src/audio/samples/C6v8.m4a differ diff --git a/src/audio/samples/C7v12.m4a b/src/audio/samples/C7v12.m4a index d3bcee5..f767403 100644 Binary files a/src/audio/samples/C7v12.m4a and b/src/audio/samples/C7v12.m4a differ diff --git a/src/audio/samples/C7v16.m4a b/src/audio/samples/C7v16.m4a index 0211360..b3a3da1 100644 Binary files a/src/audio/samples/C7v16.m4a and b/src/audio/samples/C7v16.m4a differ diff --git a/src/audio/samples/C7v4.m4a b/src/audio/samples/C7v4.m4a index a2e2d2d..a89c62b 100644 Binary files a/src/audio/samples/C7v4.m4a and b/src/audio/samples/C7v4.m4a differ diff --git a/src/audio/samples/C7v8.m4a b/src/audio/samples/C7v8.m4a index 6113888..291820e 100644 Binary files a/src/audio/samples/C7v8.m4a and b/src/audio/samples/C7v8.m4a differ diff --git a/src/audio/samples/C8v12.m4a b/src/audio/samples/C8v12.m4a index 584f5ff..08ddfb2 100644 Binary files a/src/audio/samples/C8v12.m4a and b/src/audio/samples/C8v12.m4a differ diff --git a/src/audio/samples/C8v16.m4a b/src/audio/samples/C8v16.m4a index b8d2aa8..7532240 100644 Binary files a/src/audio/samples/C8v16.m4a and b/src/audio/samples/C8v16.m4a differ diff --git a/src/audio/samples/C8v4.m4a b/src/audio/samples/C8v4.m4a index ff91df5..0376be1 100644 Binary files a/src/audio/samples/C8v4.m4a and b/src/audio/samples/C8v4.m4a differ diff --git a/src/audio/samples/C8v8.m4a b/src/audio/samples/C8v8.m4a index 32e8a04..c05557d 100644 Binary files a/src/audio/samples/C8v8.m4a and b/src/audio/samples/C8v8.m4a differ diff --git a/src/audio/samples/Dsharp1v12.m4a b/src/audio/samples/Dsharp1v12.m4a index 0f7d897..4f9f343 100644 Binary files a/src/audio/samples/Dsharp1v12.m4a and b/src/audio/samples/Dsharp1v12.m4a differ diff --git a/src/audio/samples/Dsharp1v16.m4a b/src/audio/samples/Dsharp1v16.m4a index fe422e2..24164b1 100644 Binary files a/src/audio/samples/Dsharp1v16.m4a and b/src/audio/samples/Dsharp1v16.m4a differ diff --git a/src/audio/samples/Dsharp1v4.m4a b/src/audio/samples/Dsharp1v4.m4a index 03e7208..c8065ee 100644 Binary files a/src/audio/samples/Dsharp1v4.m4a and b/src/audio/samples/Dsharp1v4.m4a differ diff --git a/src/audio/samples/Dsharp1v8.m4a b/src/audio/samples/Dsharp1v8.m4a index b5de786..c500458 100644 Binary files a/src/audio/samples/Dsharp1v8.m4a and b/src/audio/samples/Dsharp1v8.m4a differ diff --git a/src/audio/samples/Dsharp2v12.m4a b/src/audio/samples/Dsharp2v12.m4a index a2392da..e2e6cb1 100644 Binary files a/src/audio/samples/Dsharp2v12.m4a and b/src/audio/samples/Dsharp2v12.m4a differ diff --git a/src/audio/samples/Dsharp2v16.m4a b/src/audio/samples/Dsharp2v16.m4a index 264716e..3ec1be1 100644 Binary files a/src/audio/samples/Dsharp2v16.m4a and b/src/audio/samples/Dsharp2v16.m4a differ diff --git a/src/audio/samples/Dsharp2v4.m4a b/src/audio/samples/Dsharp2v4.m4a index 6984fbc..98abd9b 100644 Binary files a/src/audio/samples/Dsharp2v4.m4a and b/src/audio/samples/Dsharp2v4.m4a differ diff --git a/src/audio/samples/Dsharp2v8.m4a b/src/audio/samples/Dsharp2v8.m4a index 0461578..3427210 100644 Binary files a/src/audio/samples/Dsharp2v8.m4a and b/src/audio/samples/Dsharp2v8.m4a differ diff --git a/src/audio/samples/Dsharp3v12.m4a b/src/audio/samples/Dsharp3v12.m4a index f4d7398..659bcc6 100644 Binary files a/src/audio/samples/Dsharp3v12.m4a and b/src/audio/samples/Dsharp3v12.m4a differ diff --git a/src/audio/samples/Dsharp3v16.m4a b/src/audio/samples/Dsharp3v16.m4a index 3a48ed5..3f11fc9 100644 Binary files a/src/audio/samples/Dsharp3v16.m4a and b/src/audio/samples/Dsharp3v16.m4a differ diff --git a/src/audio/samples/Dsharp3v4.m4a b/src/audio/samples/Dsharp3v4.m4a index a3d205d..e9b749a 100644 Binary files a/src/audio/samples/Dsharp3v4.m4a and b/src/audio/samples/Dsharp3v4.m4a differ diff --git a/src/audio/samples/Dsharp3v8.m4a b/src/audio/samples/Dsharp3v8.m4a index 17b16e1..4fe08ce 100644 Binary files a/src/audio/samples/Dsharp3v8.m4a and b/src/audio/samples/Dsharp3v8.m4a differ diff --git a/src/audio/samples/Dsharp4v12.m4a b/src/audio/samples/Dsharp4v12.m4a index 42fbf3a..65f0191 100644 Binary files a/src/audio/samples/Dsharp4v12.m4a and b/src/audio/samples/Dsharp4v12.m4a differ diff --git a/src/audio/samples/Dsharp4v16.m4a b/src/audio/samples/Dsharp4v16.m4a index 2c2cd57..15e0377 100644 Binary files a/src/audio/samples/Dsharp4v16.m4a and b/src/audio/samples/Dsharp4v16.m4a differ diff --git a/src/audio/samples/Dsharp4v4.m4a b/src/audio/samples/Dsharp4v4.m4a index 9591c46..bac5a82 100644 Binary files a/src/audio/samples/Dsharp4v4.m4a and b/src/audio/samples/Dsharp4v4.m4a differ diff --git a/src/audio/samples/Dsharp4v8.m4a b/src/audio/samples/Dsharp4v8.m4a index 734a779..d55028b 100644 Binary files a/src/audio/samples/Dsharp4v8.m4a and b/src/audio/samples/Dsharp4v8.m4a differ diff --git a/src/audio/samples/Dsharp5v12.m4a b/src/audio/samples/Dsharp5v12.m4a index 9083dd0..3ea57fd 100644 Binary files a/src/audio/samples/Dsharp5v12.m4a and b/src/audio/samples/Dsharp5v12.m4a differ diff --git a/src/audio/samples/Dsharp5v16.m4a b/src/audio/samples/Dsharp5v16.m4a index 33bfab4..ef8cc27 100644 Binary files a/src/audio/samples/Dsharp5v16.m4a and b/src/audio/samples/Dsharp5v16.m4a differ diff --git a/src/audio/samples/Dsharp5v4.m4a b/src/audio/samples/Dsharp5v4.m4a index fa6c930..7eef1cf 100644 Binary files a/src/audio/samples/Dsharp5v4.m4a and b/src/audio/samples/Dsharp5v4.m4a differ diff --git a/src/audio/samples/Dsharp5v8.m4a b/src/audio/samples/Dsharp5v8.m4a index 21dce22..d4a86d5 100644 Binary files a/src/audio/samples/Dsharp5v8.m4a and b/src/audio/samples/Dsharp5v8.m4a differ diff --git a/src/audio/samples/Dsharp6v12.m4a b/src/audio/samples/Dsharp6v12.m4a index aaf59ee..d328b32 100644 Binary files a/src/audio/samples/Dsharp6v12.m4a and b/src/audio/samples/Dsharp6v12.m4a differ diff --git a/src/audio/samples/Dsharp6v16.m4a b/src/audio/samples/Dsharp6v16.m4a index 58762f4..25c28bb 100644 Binary files a/src/audio/samples/Dsharp6v16.m4a and b/src/audio/samples/Dsharp6v16.m4a differ diff --git a/src/audio/samples/Dsharp6v4.m4a b/src/audio/samples/Dsharp6v4.m4a index b617ba3..152a9b9 100644 Binary files a/src/audio/samples/Dsharp6v4.m4a and b/src/audio/samples/Dsharp6v4.m4a differ diff --git a/src/audio/samples/Dsharp6v8.m4a b/src/audio/samples/Dsharp6v8.m4a index a7704ea..bcb9da8 100644 Binary files a/src/audio/samples/Dsharp6v8.m4a and b/src/audio/samples/Dsharp6v8.m4a differ diff --git a/src/audio/samples/Dsharp7v12.m4a b/src/audio/samples/Dsharp7v12.m4a index 950034f..1fdb2af 100644 Binary files a/src/audio/samples/Dsharp7v12.m4a and b/src/audio/samples/Dsharp7v12.m4a differ diff --git a/src/audio/samples/Dsharp7v16.m4a b/src/audio/samples/Dsharp7v16.m4a index 81667cb..03ba714 100644 Binary files a/src/audio/samples/Dsharp7v16.m4a and b/src/audio/samples/Dsharp7v16.m4a differ diff --git a/src/audio/samples/Dsharp7v4.m4a b/src/audio/samples/Dsharp7v4.m4a index d49a972..43bb385 100644 Binary files a/src/audio/samples/Dsharp7v4.m4a and b/src/audio/samples/Dsharp7v4.m4a differ diff --git a/src/audio/samples/Dsharp7v8.m4a b/src/audio/samples/Dsharp7v8.m4a index c57ebae..5221103 100644 Binary files a/src/audio/samples/Dsharp7v8.m4a and b/src/audio/samples/Dsharp7v8.m4a differ diff --git a/src/audio/samples/Fsharp1v12.m4a b/src/audio/samples/Fsharp1v12.m4a index 3b941c8..369d073 100644 Binary files a/src/audio/samples/Fsharp1v12.m4a and b/src/audio/samples/Fsharp1v12.m4a differ diff --git a/src/audio/samples/Fsharp1v16.m4a b/src/audio/samples/Fsharp1v16.m4a index 71c269b..a325dbe 100644 Binary files a/src/audio/samples/Fsharp1v16.m4a and b/src/audio/samples/Fsharp1v16.m4a differ diff --git a/src/audio/samples/Fsharp1v4.m4a b/src/audio/samples/Fsharp1v4.m4a index c12ccb1..0de868d 100644 Binary files a/src/audio/samples/Fsharp1v4.m4a and b/src/audio/samples/Fsharp1v4.m4a differ diff --git a/src/audio/samples/Fsharp1v8.m4a b/src/audio/samples/Fsharp1v8.m4a index 799e5ee..b251a0e 100644 Binary files a/src/audio/samples/Fsharp1v8.m4a and b/src/audio/samples/Fsharp1v8.m4a differ diff --git a/src/audio/samples/Fsharp2v12.m4a b/src/audio/samples/Fsharp2v12.m4a index 2779ee3..7fd354e 100644 Binary files a/src/audio/samples/Fsharp2v12.m4a and b/src/audio/samples/Fsharp2v12.m4a differ diff --git a/src/audio/samples/Fsharp2v16.m4a b/src/audio/samples/Fsharp2v16.m4a index 219ab97..478084b 100644 Binary files a/src/audio/samples/Fsharp2v16.m4a and b/src/audio/samples/Fsharp2v16.m4a differ diff --git a/src/audio/samples/Fsharp2v4.m4a b/src/audio/samples/Fsharp2v4.m4a index ca98511..c1bb3c6 100644 Binary files a/src/audio/samples/Fsharp2v4.m4a and b/src/audio/samples/Fsharp2v4.m4a differ diff --git a/src/audio/samples/Fsharp2v8.m4a b/src/audio/samples/Fsharp2v8.m4a index e3a9480..1d82f4a 100644 Binary files a/src/audio/samples/Fsharp2v8.m4a and b/src/audio/samples/Fsharp2v8.m4a differ diff --git a/src/audio/samples/Fsharp3v12.m4a b/src/audio/samples/Fsharp3v12.m4a index 85424f5..6a8637a 100644 Binary files a/src/audio/samples/Fsharp3v12.m4a and b/src/audio/samples/Fsharp3v12.m4a differ diff --git a/src/audio/samples/Fsharp3v16.m4a b/src/audio/samples/Fsharp3v16.m4a index 939721f..733b52b 100644 Binary files a/src/audio/samples/Fsharp3v16.m4a and b/src/audio/samples/Fsharp3v16.m4a differ diff --git a/src/audio/samples/Fsharp3v4.m4a b/src/audio/samples/Fsharp3v4.m4a index d64957d..d8baf75 100644 Binary files a/src/audio/samples/Fsharp3v4.m4a and b/src/audio/samples/Fsharp3v4.m4a differ diff --git a/src/audio/samples/Fsharp3v8.m4a b/src/audio/samples/Fsharp3v8.m4a index 5dd56f5..bc64a87 100644 Binary files a/src/audio/samples/Fsharp3v8.m4a and b/src/audio/samples/Fsharp3v8.m4a differ diff --git a/src/audio/samples/Fsharp4v12.m4a b/src/audio/samples/Fsharp4v12.m4a index 81309f1..b45f7ed 100644 Binary files a/src/audio/samples/Fsharp4v12.m4a and b/src/audio/samples/Fsharp4v12.m4a differ diff --git a/src/audio/samples/Fsharp4v16.m4a b/src/audio/samples/Fsharp4v16.m4a index 2b60946..9475647 100644 Binary files a/src/audio/samples/Fsharp4v16.m4a and b/src/audio/samples/Fsharp4v16.m4a differ diff --git a/src/audio/samples/Fsharp4v4.m4a b/src/audio/samples/Fsharp4v4.m4a index 553e183..51c8c80 100644 Binary files a/src/audio/samples/Fsharp4v4.m4a and b/src/audio/samples/Fsharp4v4.m4a differ diff --git a/src/audio/samples/Fsharp4v8.m4a b/src/audio/samples/Fsharp4v8.m4a index 3d9454b..da96c97 100644 Binary files a/src/audio/samples/Fsharp4v8.m4a and b/src/audio/samples/Fsharp4v8.m4a differ diff --git a/src/audio/samples/Fsharp5v12.m4a b/src/audio/samples/Fsharp5v12.m4a index d09214c..65131a3 100644 Binary files a/src/audio/samples/Fsharp5v12.m4a and b/src/audio/samples/Fsharp5v12.m4a differ diff --git a/src/audio/samples/Fsharp5v16.m4a b/src/audio/samples/Fsharp5v16.m4a index b43b919..7b652dd 100644 Binary files a/src/audio/samples/Fsharp5v16.m4a and b/src/audio/samples/Fsharp5v16.m4a differ diff --git a/src/audio/samples/Fsharp5v4.m4a b/src/audio/samples/Fsharp5v4.m4a index c3eaac2..b01b1e1 100644 Binary files a/src/audio/samples/Fsharp5v4.m4a and b/src/audio/samples/Fsharp5v4.m4a differ diff --git a/src/audio/samples/Fsharp5v8.m4a b/src/audio/samples/Fsharp5v8.m4a index 79fb2f6..a8ce180 100644 Binary files a/src/audio/samples/Fsharp5v8.m4a and b/src/audio/samples/Fsharp5v8.m4a differ diff --git a/src/audio/samples/Fsharp6v12.m4a b/src/audio/samples/Fsharp6v12.m4a index b92adb7..47a5929 100644 Binary files a/src/audio/samples/Fsharp6v12.m4a and b/src/audio/samples/Fsharp6v12.m4a differ diff --git a/src/audio/samples/Fsharp6v16.m4a b/src/audio/samples/Fsharp6v16.m4a index 9b228c5..6375cec 100644 Binary files a/src/audio/samples/Fsharp6v16.m4a and b/src/audio/samples/Fsharp6v16.m4a differ diff --git a/src/audio/samples/Fsharp6v4.m4a b/src/audio/samples/Fsharp6v4.m4a index c9a1691..63367e6 100644 Binary files a/src/audio/samples/Fsharp6v4.m4a and b/src/audio/samples/Fsharp6v4.m4a differ diff --git a/src/audio/samples/Fsharp6v8.m4a b/src/audio/samples/Fsharp6v8.m4a index 7c122bd..342c344 100644 Binary files a/src/audio/samples/Fsharp6v8.m4a and b/src/audio/samples/Fsharp6v8.m4a differ diff --git a/src/audio/samples/Fsharp7v12.m4a b/src/audio/samples/Fsharp7v12.m4a index 2ad18ba..e360c30 100644 Binary files a/src/audio/samples/Fsharp7v12.m4a and b/src/audio/samples/Fsharp7v12.m4a differ diff --git a/src/audio/samples/Fsharp7v16.m4a b/src/audio/samples/Fsharp7v16.m4a index e4644a2..dc2407f 100644 Binary files a/src/audio/samples/Fsharp7v16.m4a and b/src/audio/samples/Fsharp7v16.m4a differ diff --git a/src/audio/samples/Fsharp7v4.m4a b/src/audio/samples/Fsharp7v4.m4a index f3f9787..b108ee7 100644 Binary files a/src/audio/samples/Fsharp7v4.m4a and b/src/audio/samples/Fsharp7v4.m4a differ diff --git a/src/audio/samples/Fsharp7v8.m4a b/src/audio/samples/Fsharp7v8.m4a index d9020b6..f87360e 100644 Binary files a/src/audio/samples/Fsharp7v8.m4a and b/src/audio/samples/Fsharp7v8.m4a differ diff --git a/src/audio/samples/README.md b/src/audio/samples/README.md index b37247b..c03cf89 100644 --- a/src/audio/samples/README.md +++ b/src/audio/samples/README.md @@ -19,8 +19,12 @@ anchors are A, C, Dsharp, and Fsharp for octaves 1-7, plus A0, A7, and C8. The app derives strike MIDI values and velocity layers from filenames in `piano-samples.ts`; release sample `rel1` maps to A0 and `rel88` maps to C8. -Repro notes: start from the matching OGG files in the source packages and -transcode each selected sample to AAC/M4A at 192 kbps without renaming the -note/velocity or release stem. Replace `#` with `sharp` in filenames for URL +Repro notes: start from the matching OGG files in the source packages +(~88 kbps Vorbis, 48 kHz stereo) and transcode each selected sample to +AAC/M4A at 96 kbps (`ffmpeg -i .ogg -c:a aac -b:a 96k -movflags ++faststart .m4a`) without renaming the note/velocity or release stem. +Strike samples longer than 12 seconds are faded out from 10 s to 12 s and cut +there (`-af afade=t=out:st=10:d=2 -t 12`); the sampler's own gain envelope +masks the shortened tail. Replace `#` with `sharp` in filenames for URL compatibility. Expected output filenames include `v.m4a`, for example `C4v16.m4a`, and `rel.m4a`, for example `rel40.m4a`. diff --git a/src/audio/samples/rel1.m4a b/src/audio/samples/rel1.m4a index 8cf2d5b..7ca5353 100644 Binary files a/src/audio/samples/rel1.m4a and b/src/audio/samples/rel1.m4a differ diff --git a/src/audio/samples/rel10.m4a b/src/audio/samples/rel10.m4a index 6cad512..992a39b 100644 Binary files a/src/audio/samples/rel10.m4a and b/src/audio/samples/rel10.m4a differ diff --git a/src/audio/samples/rel11.m4a b/src/audio/samples/rel11.m4a index 0b386b3..f4d300a 100644 Binary files a/src/audio/samples/rel11.m4a and b/src/audio/samples/rel11.m4a differ diff --git a/src/audio/samples/rel12.m4a b/src/audio/samples/rel12.m4a index c870544..1644c37 100644 Binary files a/src/audio/samples/rel12.m4a and b/src/audio/samples/rel12.m4a differ diff --git a/src/audio/samples/rel13.m4a b/src/audio/samples/rel13.m4a index 5849362..4c42cea 100644 Binary files a/src/audio/samples/rel13.m4a and b/src/audio/samples/rel13.m4a differ diff --git a/src/audio/samples/rel14.m4a b/src/audio/samples/rel14.m4a index 0dfc5a0..ecd4ea8 100644 Binary files a/src/audio/samples/rel14.m4a and b/src/audio/samples/rel14.m4a differ diff --git a/src/audio/samples/rel15.m4a b/src/audio/samples/rel15.m4a index 54b6acf..48ed55f 100644 Binary files a/src/audio/samples/rel15.m4a and b/src/audio/samples/rel15.m4a differ diff --git a/src/audio/samples/rel16.m4a b/src/audio/samples/rel16.m4a index 863f1ff..166368c 100644 Binary files a/src/audio/samples/rel16.m4a and b/src/audio/samples/rel16.m4a differ diff --git a/src/audio/samples/rel17.m4a b/src/audio/samples/rel17.m4a index 591ee71..b1754c9 100644 Binary files a/src/audio/samples/rel17.m4a and b/src/audio/samples/rel17.m4a differ diff --git a/src/audio/samples/rel18.m4a b/src/audio/samples/rel18.m4a index 77533bf..d737fea 100644 Binary files a/src/audio/samples/rel18.m4a and b/src/audio/samples/rel18.m4a differ diff --git a/src/audio/samples/rel19.m4a b/src/audio/samples/rel19.m4a index 89c7b27..a996d25 100644 Binary files a/src/audio/samples/rel19.m4a and b/src/audio/samples/rel19.m4a differ diff --git a/src/audio/samples/rel2.m4a b/src/audio/samples/rel2.m4a index dd5ab64..83923c8 100644 Binary files a/src/audio/samples/rel2.m4a and b/src/audio/samples/rel2.m4a differ diff --git a/src/audio/samples/rel20.m4a b/src/audio/samples/rel20.m4a index 874cbfe..b35bfc0 100644 Binary files a/src/audio/samples/rel20.m4a and b/src/audio/samples/rel20.m4a differ diff --git a/src/audio/samples/rel21.m4a b/src/audio/samples/rel21.m4a index daafbef..0a39888 100644 Binary files a/src/audio/samples/rel21.m4a and b/src/audio/samples/rel21.m4a differ diff --git a/src/audio/samples/rel22.m4a b/src/audio/samples/rel22.m4a index 0dbe681..24b8799 100644 Binary files a/src/audio/samples/rel22.m4a and b/src/audio/samples/rel22.m4a differ diff --git a/src/audio/samples/rel23.m4a b/src/audio/samples/rel23.m4a index ff51cbc..c39910c 100644 Binary files a/src/audio/samples/rel23.m4a and b/src/audio/samples/rel23.m4a differ diff --git a/src/audio/samples/rel24.m4a b/src/audio/samples/rel24.m4a index b5515e5..5854d9f 100644 Binary files a/src/audio/samples/rel24.m4a and b/src/audio/samples/rel24.m4a differ diff --git a/src/audio/samples/rel25.m4a b/src/audio/samples/rel25.m4a index 12ccd06..c8c9eea 100644 Binary files a/src/audio/samples/rel25.m4a and b/src/audio/samples/rel25.m4a differ diff --git a/src/audio/samples/rel26.m4a b/src/audio/samples/rel26.m4a index 81e3075..8c93258 100644 Binary files a/src/audio/samples/rel26.m4a and b/src/audio/samples/rel26.m4a differ diff --git a/src/audio/samples/rel27.m4a b/src/audio/samples/rel27.m4a index 25ebe1e..1625f68 100644 Binary files a/src/audio/samples/rel27.m4a and b/src/audio/samples/rel27.m4a differ diff --git a/src/audio/samples/rel28.m4a b/src/audio/samples/rel28.m4a index d49226d..dbde742 100644 Binary files a/src/audio/samples/rel28.m4a and b/src/audio/samples/rel28.m4a differ diff --git a/src/audio/samples/rel29.m4a b/src/audio/samples/rel29.m4a index 6fd7267..ab47e2a 100644 Binary files a/src/audio/samples/rel29.m4a and b/src/audio/samples/rel29.m4a differ diff --git a/src/audio/samples/rel3.m4a b/src/audio/samples/rel3.m4a index 9d67e09..b0088de 100644 Binary files a/src/audio/samples/rel3.m4a and b/src/audio/samples/rel3.m4a differ diff --git a/src/audio/samples/rel30.m4a b/src/audio/samples/rel30.m4a index 3312f64..29b9cad 100644 Binary files a/src/audio/samples/rel30.m4a and b/src/audio/samples/rel30.m4a differ diff --git a/src/audio/samples/rel31.m4a b/src/audio/samples/rel31.m4a index 2543ce7..beb8a0e 100644 Binary files a/src/audio/samples/rel31.m4a and b/src/audio/samples/rel31.m4a differ diff --git a/src/audio/samples/rel32.m4a b/src/audio/samples/rel32.m4a index b06a0f9..5aa4f29 100644 Binary files a/src/audio/samples/rel32.m4a and b/src/audio/samples/rel32.m4a differ diff --git a/src/audio/samples/rel33.m4a b/src/audio/samples/rel33.m4a index 40de0b5..92777bf 100644 Binary files a/src/audio/samples/rel33.m4a and b/src/audio/samples/rel33.m4a differ diff --git a/src/audio/samples/rel34.m4a b/src/audio/samples/rel34.m4a index 52761b1..e10a06a 100644 Binary files a/src/audio/samples/rel34.m4a and b/src/audio/samples/rel34.m4a differ diff --git a/src/audio/samples/rel35.m4a b/src/audio/samples/rel35.m4a index 3603cf2..23d44e2 100644 Binary files a/src/audio/samples/rel35.m4a and b/src/audio/samples/rel35.m4a differ diff --git a/src/audio/samples/rel36.m4a b/src/audio/samples/rel36.m4a index e16e5f4..c44f552 100644 Binary files a/src/audio/samples/rel36.m4a and b/src/audio/samples/rel36.m4a differ diff --git a/src/audio/samples/rel37.m4a b/src/audio/samples/rel37.m4a index c0c316c..65590ff 100644 Binary files a/src/audio/samples/rel37.m4a and b/src/audio/samples/rel37.m4a differ diff --git a/src/audio/samples/rel38.m4a b/src/audio/samples/rel38.m4a index 4b1496f..9d23d5f 100644 Binary files a/src/audio/samples/rel38.m4a and b/src/audio/samples/rel38.m4a differ diff --git a/src/audio/samples/rel39.m4a b/src/audio/samples/rel39.m4a index af13d13..15b84cc 100644 Binary files a/src/audio/samples/rel39.m4a and b/src/audio/samples/rel39.m4a differ diff --git a/src/audio/samples/rel4.m4a b/src/audio/samples/rel4.m4a index addaa1f..3632881 100644 Binary files a/src/audio/samples/rel4.m4a and b/src/audio/samples/rel4.m4a differ diff --git a/src/audio/samples/rel40.m4a b/src/audio/samples/rel40.m4a index 41fb5b8..61d5273 100644 Binary files a/src/audio/samples/rel40.m4a and b/src/audio/samples/rel40.m4a differ diff --git a/src/audio/samples/rel41.m4a b/src/audio/samples/rel41.m4a index bfa11c8..a047553 100644 Binary files a/src/audio/samples/rel41.m4a and b/src/audio/samples/rel41.m4a differ diff --git a/src/audio/samples/rel42.m4a b/src/audio/samples/rel42.m4a index d6439fa..d6479d0 100644 Binary files a/src/audio/samples/rel42.m4a and b/src/audio/samples/rel42.m4a differ diff --git a/src/audio/samples/rel43.m4a b/src/audio/samples/rel43.m4a index 5b94878..cd24d07 100644 Binary files a/src/audio/samples/rel43.m4a and b/src/audio/samples/rel43.m4a differ diff --git a/src/audio/samples/rel44.m4a b/src/audio/samples/rel44.m4a index ba6b1d3..d72260e 100644 Binary files a/src/audio/samples/rel44.m4a and b/src/audio/samples/rel44.m4a differ diff --git a/src/audio/samples/rel45.m4a b/src/audio/samples/rel45.m4a index 4eab6bc..fe53f29 100644 Binary files a/src/audio/samples/rel45.m4a and b/src/audio/samples/rel45.m4a differ diff --git a/src/audio/samples/rel46.m4a b/src/audio/samples/rel46.m4a index 42a0fb3..e1b1ae0 100644 Binary files a/src/audio/samples/rel46.m4a and b/src/audio/samples/rel46.m4a differ diff --git a/src/audio/samples/rel47.m4a b/src/audio/samples/rel47.m4a index b7fa1a7..de4a71c 100644 Binary files a/src/audio/samples/rel47.m4a and b/src/audio/samples/rel47.m4a differ diff --git a/src/audio/samples/rel48.m4a b/src/audio/samples/rel48.m4a index 3234c08..bb05607 100644 Binary files a/src/audio/samples/rel48.m4a and b/src/audio/samples/rel48.m4a differ diff --git a/src/audio/samples/rel49.m4a b/src/audio/samples/rel49.m4a index 6e49637..100b2ca 100644 Binary files a/src/audio/samples/rel49.m4a and b/src/audio/samples/rel49.m4a differ diff --git a/src/audio/samples/rel5.m4a b/src/audio/samples/rel5.m4a index 17c9856..c202e32 100644 Binary files a/src/audio/samples/rel5.m4a and b/src/audio/samples/rel5.m4a differ diff --git a/src/audio/samples/rel50.m4a b/src/audio/samples/rel50.m4a index dd01182..970b66f 100644 Binary files a/src/audio/samples/rel50.m4a and b/src/audio/samples/rel50.m4a differ diff --git a/src/audio/samples/rel51.m4a b/src/audio/samples/rel51.m4a index c875276..aeabd22 100644 Binary files a/src/audio/samples/rel51.m4a and b/src/audio/samples/rel51.m4a differ diff --git a/src/audio/samples/rel52.m4a b/src/audio/samples/rel52.m4a index d49ebb4..5b73c36 100644 Binary files a/src/audio/samples/rel52.m4a and b/src/audio/samples/rel52.m4a differ diff --git a/src/audio/samples/rel53.m4a b/src/audio/samples/rel53.m4a index d599e0d..3e57830 100644 Binary files a/src/audio/samples/rel53.m4a and b/src/audio/samples/rel53.m4a differ diff --git a/src/audio/samples/rel54.m4a b/src/audio/samples/rel54.m4a index 7dc6bd5..fe67f73 100644 Binary files a/src/audio/samples/rel54.m4a and b/src/audio/samples/rel54.m4a differ diff --git a/src/audio/samples/rel55.m4a b/src/audio/samples/rel55.m4a index 4534017..9f58822 100644 Binary files a/src/audio/samples/rel55.m4a and b/src/audio/samples/rel55.m4a differ diff --git a/src/audio/samples/rel56.m4a b/src/audio/samples/rel56.m4a index aac1106..2964944 100644 Binary files a/src/audio/samples/rel56.m4a and b/src/audio/samples/rel56.m4a differ diff --git a/src/audio/samples/rel57.m4a b/src/audio/samples/rel57.m4a index a6b637b..b78f42d 100644 Binary files a/src/audio/samples/rel57.m4a and b/src/audio/samples/rel57.m4a differ diff --git a/src/audio/samples/rel58.m4a b/src/audio/samples/rel58.m4a index 311e6bc..9f6c81d 100644 Binary files a/src/audio/samples/rel58.m4a and b/src/audio/samples/rel58.m4a differ diff --git a/src/audio/samples/rel59.m4a b/src/audio/samples/rel59.m4a index 6dc7ddc..5a34bdd 100644 Binary files a/src/audio/samples/rel59.m4a and b/src/audio/samples/rel59.m4a differ diff --git a/src/audio/samples/rel6.m4a b/src/audio/samples/rel6.m4a index e805093..ba233eb 100644 Binary files a/src/audio/samples/rel6.m4a and b/src/audio/samples/rel6.m4a differ diff --git a/src/audio/samples/rel60.m4a b/src/audio/samples/rel60.m4a index 60568da..86c4124 100644 Binary files a/src/audio/samples/rel60.m4a and b/src/audio/samples/rel60.m4a differ diff --git a/src/audio/samples/rel61.m4a b/src/audio/samples/rel61.m4a index 42e57d3..a5edf7c 100644 Binary files a/src/audio/samples/rel61.m4a and b/src/audio/samples/rel61.m4a differ diff --git a/src/audio/samples/rel62.m4a b/src/audio/samples/rel62.m4a index 386bc6f..88fb141 100644 Binary files a/src/audio/samples/rel62.m4a and b/src/audio/samples/rel62.m4a differ diff --git a/src/audio/samples/rel63.m4a b/src/audio/samples/rel63.m4a index a2a5fc5..afcdba7 100644 Binary files a/src/audio/samples/rel63.m4a and b/src/audio/samples/rel63.m4a differ diff --git a/src/audio/samples/rel64.m4a b/src/audio/samples/rel64.m4a index b0795b0..d0056b1 100644 Binary files a/src/audio/samples/rel64.m4a and b/src/audio/samples/rel64.m4a differ diff --git a/src/audio/samples/rel65.m4a b/src/audio/samples/rel65.m4a index c51e877..0d0ea07 100644 Binary files a/src/audio/samples/rel65.m4a and b/src/audio/samples/rel65.m4a differ diff --git a/src/audio/samples/rel66.m4a b/src/audio/samples/rel66.m4a index 7307df4..53286fd 100644 Binary files a/src/audio/samples/rel66.m4a and b/src/audio/samples/rel66.m4a differ diff --git a/src/audio/samples/rel67.m4a b/src/audio/samples/rel67.m4a index ede7dd2..98d3127 100644 Binary files a/src/audio/samples/rel67.m4a and b/src/audio/samples/rel67.m4a differ diff --git a/src/audio/samples/rel68.m4a b/src/audio/samples/rel68.m4a index 25d123f..74600b5 100644 Binary files a/src/audio/samples/rel68.m4a and b/src/audio/samples/rel68.m4a differ diff --git a/src/audio/samples/rel69.m4a b/src/audio/samples/rel69.m4a index 1102c0e..092ef5c 100644 Binary files a/src/audio/samples/rel69.m4a and b/src/audio/samples/rel69.m4a differ diff --git a/src/audio/samples/rel7.m4a b/src/audio/samples/rel7.m4a index 91f5ef6..d86edfb 100644 Binary files a/src/audio/samples/rel7.m4a and b/src/audio/samples/rel7.m4a differ diff --git a/src/audio/samples/rel70.m4a b/src/audio/samples/rel70.m4a index 7771d47..4d92658 100644 Binary files a/src/audio/samples/rel70.m4a and b/src/audio/samples/rel70.m4a differ diff --git a/src/audio/samples/rel71.m4a b/src/audio/samples/rel71.m4a index 03fcfd4..77c6bab 100644 Binary files a/src/audio/samples/rel71.m4a and b/src/audio/samples/rel71.m4a differ diff --git a/src/audio/samples/rel72.m4a b/src/audio/samples/rel72.m4a index f945bb9..5b83641 100644 Binary files a/src/audio/samples/rel72.m4a and b/src/audio/samples/rel72.m4a differ diff --git a/src/audio/samples/rel73.m4a b/src/audio/samples/rel73.m4a index 104ba8d..7a5d28d 100644 Binary files a/src/audio/samples/rel73.m4a and b/src/audio/samples/rel73.m4a differ diff --git a/src/audio/samples/rel74.m4a b/src/audio/samples/rel74.m4a index 88c6f8d..6493a9d 100644 Binary files a/src/audio/samples/rel74.m4a and b/src/audio/samples/rel74.m4a differ diff --git a/src/audio/samples/rel75.m4a b/src/audio/samples/rel75.m4a index 8e32dd2..4397728 100644 Binary files a/src/audio/samples/rel75.m4a and b/src/audio/samples/rel75.m4a differ diff --git a/src/audio/samples/rel76.m4a b/src/audio/samples/rel76.m4a index e95f09d..df7c27c 100644 Binary files a/src/audio/samples/rel76.m4a and b/src/audio/samples/rel76.m4a differ diff --git a/src/audio/samples/rel77.m4a b/src/audio/samples/rel77.m4a index dab0b10..478f1d0 100644 Binary files a/src/audio/samples/rel77.m4a and b/src/audio/samples/rel77.m4a differ diff --git a/src/audio/samples/rel78.m4a b/src/audio/samples/rel78.m4a index 0c9808c..662dc2c 100644 Binary files a/src/audio/samples/rel78.m4a and b/src/audio/samples/rel78.m4a differ diff --git a/src/audio/samples/rel79.m4a b/src/audio/samples/rel79.m4a index 75d2f1e..9184127 100644 Binary files a/src/audio/samples/rel79.m4a and b/src/audio/samples/rel79.m4a differ diff --git a/src/audio/samples/rel8.m4a b/src/audio/samples/rel8.m4a index 69c5036..d2b9530 100644 Binary files a/src/audio/samples/rel8.m4a and b/src/audio/samples/rel8.m4a differ diff --git a/src/audio/samples/rel80.m4a b/src/audio/samples/rel80.m4a index f43ae99..4013bdf 100644 Binary files a/src/audio/samples/rel80.m4a and b/src/audio/samples/rel80.m4a differ diff --git a/src/audio/samples/rel81.m4a b/src/audio/samples/rel81.m4a index 7a6198f..a365a87 100644 Binary files a/src/audio/samples/rel81.m4a and b/src/audio/samples/rel81.m4a differ diff --git a/src/audio/samples/rel82.m4a b/src/audio/samples/rel82.m4a index 19a1c8e..19bb91e 100644 Binary files a/src/audio/samples/rel82.m4a and b/src/audio/samples/rel82.m4a differ diff --git a/src/audio/samples/rel83.m4a b/src/audio/samples/rel83.m4a index 78ca8a2..c6f5838 100644 Binary files a/src/audio/samples/rel83.m4a and b/src/audio/samples/rel83.m4a differ diff --git a/src/audio/samples/rel84.m4a b/src/audio/samples/rel84.m4a index 3f4d8c5..5a26fb4 100644 Binary files a/src/audio/samples/rel84.m4a and b/src/audio/samples/rel84.m4a differ diff --git a/src/audio/samples/rel85.m4a b/src/audio/samples/rel85.m4a index afa6e8e..edbe215 100644 Binary files a/src/audio/samples/rel85.m4a and b/src/audio/samples/rel85.m4a differ diff --git a/src/audio/samples/rel86.m4a b/src/audio/samples/rel86.m4a index 26977b1..990ba31 100644 Binary files a/src/audio/samples/rel86.m4a and b/src/audio/samples/rel86.m4a differ diff --git a/src/audio/samples/rel87.m4a b/src/audio/samples/rel87.m4a index 666d1d8..4f98e79 100644 Binary files a/src/audio/samples/rel87.m4a and b/src/audio/samples/rel87.m4a differ diff --git a/src/audio/samples/rel88.m4a b/src/audio/samples/rel88.m4a index 6045663..bc4f12b 100644 Binary files a/src/audio/samples/rel88.m4a and b/src/audio/samples/rel88.m4a differ diff --git a/src/audio/samples/rel9.m4a b/src/audio/samples/rel9.m4a index 1d2be34..7c0e4cf 100644 Binary files a/src/audio/samples/rel9.m4a and b/src/audio/samples/rel9.m4a differ diff --git a/src/index.ts b/src/index.ts index 79b5251..d1f347a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -156,8 +156,10 @@ const main = async () => { } }); - // Samples load before Start is enabled so the first audible piano note - // always uses the sampler. The Start tap still unlocks the AudioContext. + // Only the core velocity layer loads before Start is enabled so the first + // audible piano note always uses the sampler; the remaining layers and + // release samples stream in the background. The Start tap still unlocks + // the AudioContext. splash.showLoadingBar(); const fontsReady = document.fonts.ready.catch((error) => { ErrorHandler.addException(error, {