Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ export default defineConfig([
// Variables
'no-var': 'error',
'prefer-const': 'error',
'@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }],

// Naming conventions
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'default',
format: ['camelCase'],
leadingUnderscore: 'forbid',
leadingUnderscore: 'allow',
trailingUnderscore: 'forbid',
},
{
Expand Down
5 changes: 3 additions & 2 deletions src/audio/PlaylistManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Fade } from '../../types/Fade';
import { FadeType } from '../../types/Fade';
import type { ID, Seconds, PlaylistEntry, Transition, ScheduledEntry } from './types';

/**
Expand Down Expand Up @@ -118,7 +119,7 @@ export class PlaylistManager {
if (i > 0) {
const prevEntry = this.entries[i - 1];
const incomingTransition = this.getTransitionBetween(prevEntry.id, entry.id);
if (incomingTransition) {
if (incomingTransition && incomingTransition.fadeInType !== FadeType.NONE) {
fades.push({
type: incomingTransition.fadeInType,
startOffset: 0,
Expand All @@ -133,7 +134,7 @@ export class PlaylistManager {
if (i < this.entries.length - 1) {
const nextEntry = this.entries[i + 1];
const outgoingTransition = this.getTransitionBetween(entry.id, nextEntry.id);
if (outgoingTransition) {
if (outgoingTransition && outgoingTransition.fadeOutType !== FadeType.NONE) {
fades.push({
type: outgoingTransition.fadeOutType,
startOffset: entry.duration - outgoingTransition.duration,
Expand Down
18 changes: 18 additions & 0 deletions src/audio/Scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ const SCHEDULE_AHEAD_S: Seconds = 0.2;
/** grace period, nodes within this window of ctx.currentTime are considered "audible" */
const AUDIBLE_GRACE_S = 0.05;

const EQUAL_POWER_CURVE_LENGTH = 128;

// fade-out: cos(t * pi/2), 1 -> 0
const EQUAL_POWER_FADE_OUT = new Float32Array(EQUAL_POWER_CURVE_LENGTH).map((_, i) =>
Math.cos((i / (EQUAL_POWER_CURVE_LENGTH - 1)) * (Math.PI / 2)),
);
// fade-in: sin(t * pi/2), 0 -> 1
const EQUAL_POWER_FADE_IN = new Float32Array(EQUAL_POWER_CURVE_LENGTH).map((_, i) =>
Math.sin((i / (EQUAL_POWER_CURVE_LENGTH - 1)) * (Math.PI / 2)),
);

/**
* Look-ahead scheduler
*
Expand Down Expand Up @@ -385,6 +396,13 @@ export class Scheduler {

if (fade.type === FadeType.LINEAR) {
gainNode.gain.linearRampToValueAtTime(Math.max(fade.endGain, 0.0001), fadeEndCtx);
} else if (fade.type === FadeType.EQUAL_POWER) {
const isFadeIn = fade.endGain > fade.startGain;
const fullCurve = isFadeIn ? EQUAL_POWER_FADE_IN : EQUAL_POWER_FADE_OUT;
// slice from the fraction we've already passed (mid-fade seek)
const startIdx = Math.round(fadeFraction * (EQUAL_POWER_CURVE_LENGTH - 1));
const curve = startIdx > 0 ? fullCurve.slice(startIdx) : fullCurve;
gainNode.gain.setValueCurveAtTime(curve, fadeStartCtx, fadeEndCtx - fadeStartCtx);
} else {
// exponentialRamp can't reach 0, so we use an epsilon
gainNode.gain.exponentialRampToValueAtTime(Math.max(fade.endGain, 0.0001), fadeEndCtx);
Expand Down
6 changes: 4 additions & 2 deletions types/Fade.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type {Seconds, Gain} from "./UtilTypes"

export const FadeType = {
LINEAR: 0,
EXPONENTIAL: 1,
NONE: 0,
LINEAR: 1,
EXPONENTIAL: 2,
EQUAL_POWER: 3,
} as const;

export type FadeType = (typeof FadeType)[keyof typeof FadeType];
Expand Down
Loading