Я выполнил следующие шаги:
- Я использовал функцию
transform
из библиотеки nayuki fft для преобразования аудиосэмплов в серию комплексных чисел, представляющих частотную область, - I затем
unshifted
индексы всех значений выросли на 40000 - После этого я использовал
inverseTranform
из той же библиотеки для преобразования данных в частотной области обратно в волну. - Я сыграл ее с
Web Audio API
и сравнил.
Я обнаружил, что смещение всех индексов на 40000 практически не влияет на окончательный звук. Учитывая, что я заменил нижние 40 000 индексов, а общий массив длиной 96 000 элементов, данные в массиве после выполнения unshift
существенно отличались от того, что было до unshift
. Я подумал, что это будет означать, что после того, как я построю новую звуковую волну из сильно измененных частотных данных, у меня получится нечто существенно отличающееся (надеюсь, версия оригинала со смещением высоты тона).
Вот jsFiddle: https://jsfiddle.net/vj4dr7wc/1/.
Вот важный раздел скрипта:
//** Do processing **//
console.log(">>>>>Buffer>>>>>");
//console.log(Array.isArray(nowBuffering));
console.log(buffer[0],buffer[1]);
// Calculate fft of buffer
console.log("=====FrequencyInfo====");
var freqInfo = [buffer[0].slice(),buffer[1].slice()];
transform(freqInfo[0],freqInfo[1])
console.log(freqInfo[0],freqInfo[1]);
// Do effects
console.log("^^^^^^Pitch Effects^^^^^^^");
var beforeEffect = freqInfo[0].slice();
pitchEffects(channel,freqInfo);
console.log(beforeEffect);
console.log("!=");
console.log(freqInfo[0]);
console.log(freqInfo[0]==beforeEffect);
// Reconstruct waveform
console.log("~~~~~~Reconstructed~~~~~~~");
var reconstred = [freqInfo[0].slice(),freqInfo[1].slice()];
inverseTransform(reconstred[0],reconstred[1]);
// Normalize it
var max = Math.max(...reconstred[0]);
var maxOrig = Math.max(...buffer[0]);
console.log("max: "+max);
reconstred[0] = reconstred[0].map(function(value){
return (maxOrig/max)*value;
});
// Save it
var reconBuffer = audioBuffer1.getChannelData(channel);
for (var i = 0; i < frameCount; i++) {
reconBuffer[i] = reconstred[0][i];
}
console.log(reconstred[0],reconstred[1]);
// Check results
console.log("*******Results********");
console.log(reconstred[0]==buffer[0]);
console.log(reconstred[0]);
console.log("==");
console.log(buffer[0]);
//** End Processing **//
Вот полный рабочий пример (требуется fft.js
):
<code><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<script src="fft.js"></script>
<title>Audio Test</title>
<link rel="stylesheet" href="">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<h1>Audio Test</h1>
<button id='0'>Play original sound</button>
<button id='1'>Play reconstructed sound</button>
<pre>
подключения (audioCtx.destination); song.start (); song.onended = () => {console.log («Восстановленный звук закончен»); }} buttonOriginal.onclick = function () {var song = audioCtx.createBufferSource (); song.buffer = audioBuffer0; song.connect (audioCtx.destination); song.start (); song.onended = () => {console.log ('Оригинальный звук закончен'); }} function freqSin (freq, time) {return Math.sin (freq * (2 * pi) * time); } var currentPitchShift = 0; function pitchEffects (channel, freqInfo) {pitchShiftUp (freqInfo, 40000); } function pitchShiftUp (freqInfo, num) {var arrLen = freqInfo [0] .length; console.log ("arrLen:" + arrLen); // построить массив из 0 переменных var zeros = []; для (var i = 0; i