File size: 1,892 Bytes
a0fcd39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * Audio graph utilities for Web Audio API.
 *
 * This module provides helper functions for creating and managing
 * the audio processing graph used in the stem mixer.
 */

/**
 * Create a gain node with initial value.
 */
export function createGain(context, value = 1) {
  const gain = context.createGain()
  gain.gain.setValueAtTime(value, context.currentTime)
  return gain
}

/**
 * Create an analyser node for visualization.
 */
export function createAnalyser(context, fftSize = 128) {
  const analyser = context.createAnalyser()
  analyser.fftSize = fftSize
  analyser.smoothingTimeConstant = 0.8
  return analyser
}

/**
 * Create a simple audio graph for a single stem.
 *
 * source -> gainNode -> masterGain
 */
export function createStemGraph(context, buffer, gainNode, masterGain) {
  const source = context.createBufferSource()
  source.buffer = buffer
  source.connect(gainNode)
  gainNode.connect(masterGain)
  return source
}

/**
 * Smoothly transition a gain value.
 */
export function fadeGain(gainNode, targetValue, duration = 0.05) {
  const now = gainNode.context.currentTime
  gainNode.gain.linearRampToValueAtTime(targetValue, now + duration)
}

/**
 * Get frequency data from analyser as normalized values (0-1).
 */
export function getFrequencyData(analyser) {
  const data = new Uint8Array(analyser.frequencyBinCount)
  analyser.getByteFrequencyData(data)
  return Array.from(data).map(v => v / 255)
}

/**
 * Calculate RMS level from audio data.
 */
export function calculateRMS(audioData) {
  let sum = 0
  for (let i = 0; i < audioData.length; i++) {
    sum += audioData[i] * audioData[i]
  }
  return Math.sqrt(sum / audioData.length)
}

/**
 * Convert decibels to linear gain.
 */
export function dbToGain(db) {
  return Math.pow(10, db / 20)
}

/**
 * Convert linear gain to decibels.
 */
export function gainToDb(gain) {
  return 20 * Math.log10(gain)
}