我不熟悉 Tone.js,所以可能有更好的方法来做到这一点。您使用的数组速记的官方示例似乎不起作用,因此可能是库问题。
至于您要实现的目标,出于好奇,我摆弄了它,这就是我的想法:
function timeFromDurations(value, i, arr) {
const prevTime = arr[i - 1]?.time;
value.time = prevTime + arr[i - 1]?.duration || 0;
return value;
}
const notesAndDurations = [
{ note: 'C3', duration: .25 },
{ note: 'C4', duration: .5 },
{ note: 'G2', duration: 1 },
].map(timeFromDurations);
console.log(notesAndDurations);
const synth = new Tone.Synth().toDestination();
// use an array of objects as long as the object has a "time" attribute
const part = new Tone.Part((time, value) => {
// the value is an object which contains both the note and the velocity
synth.triggerAttackRelease(value.note, value.duration, time);
}, notesAndDurations).start(0);
Tone.Transport.start();
这个想法是您需要根据前一个音符的开始时间+持续时间来设置每个音符的开始时间。这消除了手动设置开始时间(非可选)的需要。
编辑
对于持续时间和注释位于单独数组中的第二种情况,您可以使用以下 reduce 函数:
const notes = ['C3', 'C4', 'G2'];
const durations = [0.25, 0.5, 1];
const noteDurationTime = notes.reduce((acc, note, i) => {
const prevTime = acc[i - 1]?.time;
const time = prevTime + acc[i - 1]?.duration || 0;
const duration = durations[i];
acc.push({ note, duration, time });
return acc;
}, []);
这个想法是一样的,你正在构建一个对象数组,这些对象具有所有需要的属性(note、duration、time),但这次来自不同的来源(notes 数组和 durations 数组)。
您要确保这两个数组的长度相同。