You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于JavaScript实现MIDI信号不均等间隔发送的技术咨询

嘿,我明白你要做的事儿——在固定总时长内发送指定数量的MIDI信号,但要让间隔是递增或递减的,而不是均匀的。这其实是个典型的时序加权分配问题,我给你一套具体的实现思路和代码,你可以直接拿去用或者调整。

核心思路解析

首先,均匀间隔的逻辑很直接:间隔时长 = 总时长 / 信号数量。但非均匀模式下,我们需要给每个间隔分配一个「权重」——权重越大,间隔越长(递增模式下后面的权重更高,递减模式下前面的权重更高)。然后用总权重之和作为分母,每个间隔的实际时长就是 (总时长 / 总权重) * 该间隔权重,这样所有间隔加起来的总时长必然等于你设定的值,完美满足需求。

可复用代码实现

1. 生成非均匀间隔数组的函数

这个函数负责根据你指定的模式,计算出每个信号之间的等待时长:

// 生成非均匀间隔数组(单位:毫秒)
function generateIntervals(totalTime, signalCount, mode = 'linear-increase') {
  const intervals = [];
  let totalWeight = 0;
  const weights = [];

  // 为每个间隔生成对应权重
  for (let i = 1; i <= signalCount; i++) {
    let weight;
    switch(mode) {
      case 'linear-increase':
        weight = i; // 线性递增:第1个间隔权重1,第2个2,以此类推
        break;
      case 'linear-decrease':
        weight = signalCount - i + 1; // 线性递减:第1个权重=信号数,最后一个=1
        break;
      case 'quadratic-increase':
        weight = i ** 2; // 二次递增:间隔增长速度比线性更快
        break;
      case 'quadratic-decrease':
        weight = (signalCount - i + 1) ** 2; // 二次递减
        break;
      case 'exponential-increase':
        weight = Math.pow(2, i); // 指数递增,间隔增长极快
        break;
      default:
        weight = 1; // 默认回退到均匀间隔
    }
    weights.push(weight);
    totalWeight += weight;
  }

  // 将权重转换为实际时长
  for (const weight of weights) {
    intervals.push((totalTime / totalWeight) * weight);
  }

  return intervals;
}

2. 发送MIDI信号的时序控制

有了间隔数组后,我们可以用两种方式实现时序控制:一种是简单的setTimeout(适合对精度要求不高的场景),另一种是requestAnimationFrame(精度更高,适合音乐类对时序敏感的场景)。

方式一:使用setTimeout

// 模拟实际发送MIDI信号的函数(替换成你的Web MIDI API逻辑)
function sendMidiSignal(signalIndex) {
  console.log(`发送第${signalIndex + 1}个MIDI信号`);
  // 示例:如果你用Web MIDI API,这里可以调用output.send([...])
}

// 按非均匀间隔发送信号的主函数
function sendMidiSequence(totalTime, signalCount, mode) {
  const intervals = generateIntervals(totalTime, signalCount, mode);
  let currentDelay = 0;

  intervals.forEach((interval, index) => {
    setTimeout(() => {
      sendMidiSignal(index);
    }, currentDelay);
    currentDelay += interval;
  });
}

// 调用示例:5秒内发送10个信号,采用线性递增模式
sendMidiSequence(5000, 10, 'linear-increase');

方式二:使用requestAnimationFrame(高精度)

function sendMidiSequenceRAF(totalTime, signalCount, mode) {
  const intervals = generateIntervals(totalTime, signalCount, mode);
  const startTime = performance.now();
  let currentIndex = 0;
  let nextTriggerTime = intervals[0];

  function checkTiming(currentTime) {
    if (currentIndex >= signalCount) return;

    const elapsed = currentTime - startTime;
    if (elapsed >= nextTriggerTime) {
      sendMidiSignal(currentIndex);
      currentIndex++;
      if (currentIndex < signalCount) {
        nextTriggerTime += intervals[currentIndex];
      }
    }

    requestAnimationFrame(checkTiming);
  }

  requestAnimationFrame(checkTiming);
}

// 调用示例:3秒内发送8个信号,二次递减模式
sendMidiSequenceRAF(3000, 8, 'quadratic-decrease');
自定义扩展

如果你需要更个性化的间隔曲线(比如先慢后快再慢),只需要修改generateIntervals里的权重计算逻辑就行。比如你可以用正弦函数生成权重:

// 示例:先递增后递减的正弦曲线权重
case 'sine-curve':
  // 生成0到π的正弦值,映射为权重(先增后减)
  weight = Math.sin((i / signalCount) * Math.PI);
  break;

只要保证每个间隔的权重是正数,最终的总时长都会严格等于你设定的totalTime。

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:25:31