Created
April 27, 2023 08:29
-
-
Save eliassjogreen/6a1c3fac2ac1090a014c32748153cbaa to your computer and use it in GitHub Desktop.
expo-av fade
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Audio } from "expo-av"; | |
export function linear(n: number): [number, number] { | |
return [1 - n, n]; | |
} | |
export function halfsine(n: number): [number, number] { | |
return [1 - Math.sin(n * Math.PI * 0.5), Math.sin(n * Math.PI * 0.5)]; | |
} | |
export function instant(n: number): [number, number] { | |
return [n < 0.5 ? 1 : 0, n > 0.5 ? 1 : 0]; | |
} | |
export interface FadeOptions { | |
duration: number; | |
shape: (n: number) => [number, number]; | |
} | |
export const defaultFadeOptions: FadeOptions = { | |
volume: 1, | |
duration: 5000, | |
interval: 100, | |
shape: linear, | |
}; | |
/** | |
* Fades two audio sources together over a specified {@link duration} in | |
* {@link interval time steps} using it's {@link shape} method into a final | |
* specified {@link volume}. | |
*/ | |
export async function fade( | |
a: Audio.Sound, | |
b: Audio.Sound, | |
options?: Partial<FadeOptions> | |
): Promise<void> { | |
const volume = options.volume ?? defaultFadeOptions.volume; | |
const duration = options.duration ?? defaultFadeOptions.duration; | |
const interval = options.interval ?? defaultFadeOptions.interval; | |
const shape = options.shape ?? defaultFadeOptions.shape; | |
return new Promise((resolve) => { | |
let elapsed = 0; | |
b.playAsync(); | |
const id = setInterval(() => { | |
elapsed += interval; | |
if (elapsed > duration || !a._loaded || !b._loaded) { | |
// Make sure that both sounds end up at the proper volume. | |
if (a._loaded) { | |
a.setVolumeAsync(0); | |
} | |
if (b._loaded) { | |
b.setVolumeAsync(volume); | |
} | |
clearInterval(id); | |
resolve(); | |
return; | |
} | |
const n = elapsed / duration; | |
const volumes = shape(n); | |
// Set the volumes to the absolute volume calculated by the step scaled to the target volume | |
Promise.all([a.setVolumeAsync(volumes[0] * volume), b.setVolumeAsync(volumes[1] * volume)]); | |
}, interval); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment