因为音乐速度和音高是耦合在一起的,如果我加速音乐,音高也会增加。相反,如果我放慢音乐的速度,音高也会下降。
然而,I saw that using granular synthesis, I can decouple speed and pitch.因此,我目前正在努力实现粒度合成。
首先,我认为我成功地实现了双速和半速,而球场是一样的。代码与以下代码相同:
※晶粒尺寸为2 0 0 0。这意味着我用0.04ms的声音作为一颗谷物。(2000年样本*1s/ 44100样本= 0.04s =40毫秒)
// get music
const $fileInput = document.createElement('input');
$fileInput.setAttribute('type', 'file');
document.body.appendChild($fileInput);
$fileInput.addEventListener('change', async (e) => {
const music = await $fileInput.files[0].arrayBuffer();
const actx = new (window.AudioContext || window.webkitAudioContext)({ latencyHint: 'playback', sampleRate: 44100 });
const audioData = await actx.decodeAudioData(music);
const original = audioData.getChannelData(0);
const arr = [];
const grainSize = 2000;
// Please choose one code out of double speed code or half speed code
// copy and paste audio processing code here
});// double speed
// ex: [0,1,2,3, 4,5,6,7, 8] => [0,1, 4,5, 8] discard 2 items out of 4 items
for (let i = 0; i < original.length; i += grainSize) {
if (original[i + (grainSize / 2) - 1] !== undefined) {
for (let j = 0; j < grainSize / 2; j++) {
arr.push(original[i + j]);
}
} else {
for (let j = i; j < original.length; j++) {
arr.push(j);
}
}
}// half speed
// ex: [0,1, 2,3, 4] => [0,1,0,0, 2,3,0,0, 4,0,0] add 'two' zeros after every 'two' items
for (let i = 0; i < original.length; i += grainSize) {
if (original[i + grainSize - 1] !== undefined) {
for (let j = 0; j < grainSize; j++) {
arr.push(original[i + j]);
}
} else {
for (let j = i; j < original.length; j++) {
arr.push(original[j]);
}
}
for (let j = 0; j < grainSize; j++) {
arr.push(0);
}
}// play sound
const f32Arr = Float32Array.from(arr);
const audioBuffer = new AudioBuffer({ length: arr.length, numberOfChannels: 1, sampleRate: actx.sampleRate });
audioBuffer.copyToChannel(f32Arr, 0);
const absn = new AudioBufferSourceNode(actx, { buffer: audioBuffer });
absn.connect(actx.destination);
absn.start();但是问题是,我完全不知道如何实现螺距移位器(即不同的螺距,相同的速度)。
就我看来,同样的速度意味着相同的AudioBuffer大小。因此,我手中唯一的变量是晶粒大小。但我真的不知道该怎么办。如果你能分享你的一些知识,我们将不胜感激。非常感谢!
致菲尔·弗里霍夫纳
你好,谢谢你的善意解释。我试过你的方法。据我所知,您的方法是一个执行以下操作的过程:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // input data (10 samples)
→ [0, 2, 4, 6, 8] // double speed, 1 octave high (sampling interval: 2)
→ [0, 0, 2, 2, 4, 4, 6, 6, 8, 8] // change duration结果是1倍频程高,同样的持续时间(成功的音高移动)。但是,如果我从采样间隔为1.5的输入数据进行采样,我不知道该怎么办?我的意思是,我不知道如何使[0, 1, 3, 4, 6, 7, 9]的长度与输入数据的长度相同。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // input data
// from
[0, 1, 3, 4, 6, 7, 9] // sampling interval: 1.5
// to
[?, ?, ?, ?, ?, ?, ?, ?, ?, ?]同时,我了解到音高转换可以通过一种方式来实现,据我所知,方法如下:
此外,我发现,如果我转换如下输入数据,我可以实现音高移位和时间拉伸:
input data = [0, 1, 2, 3, 4, 5, 6, 7]
grain size = 4
<pitch shifting>
in case of p = 2
result = [0, 2, 0, 2, 4, 6, 4, 6] // sounds like one octave high
// If I remember correctly, [0, 2, 0, 0, 4, 6, 0, 0] is also fine
// (and it is more fit to the definition above ([1] and [2])
// but the sound was not good (stuttering).
// I found that [0, 2, 0, 2...] is better.
in case of p = 1.5
result = [0, 1, 3, 0, 4, 5, 7, 4]
in case of p = 0.5
result = [0, 0, 1, 1, 4, 4, 5, 5] // sounds like one octave low
<time stretching>
in case of speed = 2
result = [0, 1, 4, 5]
in case of speed = 1.2
result = [0, 1, 2, 4, 5, 6]
in case of speed = 0.5
result = [0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7]
// If I remember correctly, [0, 1, 2, 3, 0, 0, 0, 0...] is also fine
// but the sound was not good (stuttering)
in case of speed = 0.75
result = [0, 1, 2, 3, 0, 4, 5, 6, 7, 4]不管怎样,谢谢你的回答。
https://stackoverflow.com/questions/71249756
复制相似问题