Подтвердить что ты не робот

Создание звука "на лету" с помощью javascript/html5

Можно ли генерировать постоянный звуковой поток с помощью javascript/html5? Например, чтобы генерировать вечную синусоидальную волну, у меня будет функция обратного вызова, которая будет вызываться всякий раз, когда выходной буфер собирается стать пустым:

function getSampleAt(timestep)
{
    return Math.sin(timestep);
}

(Идея состоит в том, чтобы использовать это для создания интерактивного синтезатора. Я не знаю заранее, как долго будет нажиматься клавиша, поэтому я не могу использовать буфер фиксированной длины)

4b9b3361

Ответ 1

Использование аудио-элемента HTML5

В настоящее время невозможно использовать генераторный звук с расширенным браузером с использованием JavaScript и элемент audio, как отмечает Стивен Уиттенс в сообщении в блоге о создании синтезатора JavaScript:

"... нет возможности помещать в очередь фрагменты синтезированного аудио для бесшовного воспроизведения".

Использование API веб-аудио

API веб-аудио был разработан для облегчения синтеза аудио JavaScript. В Mozilla Developer Network есть веб-генератор тональных сигналов, который работает в Firefox 4+ [demo 1]. Добавьте эти две строки к этому коду, и у вас есть рабочий синтезатор с генеративным устойчивым звуком при нажатии клавиши [demo 2 - работает только в Firefox 4, сначала нажмите область "Результаты", затем нажмите любую клавишу]:

window.onkeydown = start;  
window.onkeyup = stop;

Страница BBC в API веб-аудио также заслуживает рассмотрения. К сожалению, поддержка Web Audio API еще не распространяется на другие браузеры.

Возможные обходные пути

Чтобы создать кросс-браузерный синтезатор в настоящее время, вам, вероятно, придется отказаться от предварительно записанного звука с помощью:

  • Использование длинных предварительно записанных тонов образца ogg/mp3, встраивание их в отдельные элементы audio и запуск и остановка их при нажатии клавиши.
  • Вставка SWF файла, содержащего аудио-элементы, и управление воспроизведением через JavaScript. (Это, по-видимому, метод, который использует Google Les Paul Doodle.)

Ответ 2

В большинстве браузеров теперь можно использовать Web Audio API (кроме IE и Opera Mini).

Попробуйте этот код:

// one context per document
var context = new (window.AudioContext || window.webkitAudioContext)();
var osc = context.createOscillator(); // instantiate an oscillator
osc.type = 'sine'; // this is the default - also square, sawtooth, triangle
osc.frequency.value = 440; // Hz
osc.connect(context.destination); // connect it to the destination
osc.start(); // start the oscillator
osc.stop(context.currentTime + 2); // stop 2 seconds after the current time

Ответ 3

Web Audio API подходит для Chrome. См. http://googlechrome.github.io/web-audio-samples/samples/audio/index.html

Следуйте инструкциям в разделе "Начало работы", а затем просмотрите очень впечатляющие демонстрации.

Обновление (2017):, теперь это гораздо более зрелый интерфейс. API задокументирован в https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API

Ответ 4

Конечно! Вы можете использовать синтезатор тона в этой демонстрации:

enter image description here

audioCtx = new(window.AudioContext || window.webkitAudioContext)();

show();

function show() {
  frequency = document.getElementById("fIn").value;
  document.getElementById("fOut").innerHTML = frequency + ' Hz';

  switch (document.getElementById("tIn").value * 1) {
    case 0: type = 'sine'; break;
    case 1: type = 'square'; break;
    case 2: type = 'sawtooth'; break;
    case 3: type = 'triangle'; break;
  }
  document.getElementById("tOut").innerHTML = type;

  volume = document.getElementById("vIn").value / 100;
  document.getElementById("vOut").innerHTML = volume;

  duration = document.getElementById("dIn").value;
  document.getElementById("dOut").innerHTML = duration + ' ms';
}

function beep() {
  var oscillator = audioCtx.createOscillator();
  var gainNode = audioCtx.createGain();

  oscillator.connect(gainNode);
  gainNode.connect(audioCtx.destination);

  gainNode.gain.value = volume;
  oscillator.frequency.value = frequency;
  oscillator.type = type;

  oscillator.start();

  setTimeout(
    function() {
      oscillator.stop();
    },
    duration
  );
};
frequency
<input type="range" id="fIn" min="40" max="6000" oninput="show()" />
<span id="fOut"></span><br>
type
<input type="range" id="tIn" min="0" max="3" oninput="show()" />
<span id="tOut"></span><br>
volume
<input type="range" id="vIn" min="0" max="100" oninput="show()" />
<span id="vOut"></span><br>
duration
<input type="range" id="dIn" min="1" max="5000" oninput="show()" />
<span id="dOut"></span>
<br>
<button onclick='beep();'>Play</button>

Ответ 5

Вы можете сгенерировать файл wav-e на лету и воспроизвести его (src)

// Legend
// DUR - duration in seconds   SPS - sample per second (default 44100)
// NCH - number of channels    BPS - bytes per sample

// t - is number from range [0, DUR), return number in range [0, 1]
function getSampleAt(t,DUR,SPS)
{
    return Math.sin(6000*t); 
}

function genWAVUrl(fun, DUR=1, NCH=1, SPS=44100, BPS=1) {
  let size = DUR*NCH*SPS*BPS; 
  let put = (n,l=4) => [(n<<24),(n<<16),(n<<8),n].filter((x,i)=>i<l).map(x=> String.fromCharCode(x>>>24)).join('');
  let p = (...a) => a.map( b=> put(...[b].flat()) ).join(''); 
  let data = 'RIFF${put(44+size)}WAVEfmt ${p(16,[1,2],[NCH,2],SPS,NCH*BPS*SPS,[NCH*BPS,2],[BPS*8,2])}data${put(size)}'
  
  for (let i = 0; i < DUR*SPS; i++) {
    let f= Math.min(Math.max(fun(i/SPS,DUR,SPS),0),1);
    data += put(Math.floor( f * (2**(BPS*8)-1)), BPS);
  }
  
  return "data:Audio/WAV;base64," + btoa(data);
}


var WAV = new Audio( genWAVUrl(getSampleAt,5) ); // 5s
WAV.setAttribute("controls", "controls");
document.body.appendChild(WAV);
//WAV.play()

Ответ 6

Это не реальный ответ на ваш вопрос, потому что вы попросили JavaScript-решение, но вы можете использовать ActionScript. Он должен работать на всех основных браузерах.

Вы можете вызвать функции ActionScript из JavaScript.

Таким образом, вы можете обернуть функции генерации звука ActionScript и выполнить им реализацию JavaScript. Просто используйте Adobe Flex для создания крошечного swf, а затем используйте это как бэкэнд для своего кода JavaScript.

Ответ 7

Это то, что я искал вечно, и в итоге мне удалось сделать это самому, как я хотел. Может тебе тоже понравится. Простой слайдер с частотой и нажатием вкл/выкл:

buttonClickResult = function () {
	var button = document.getElementById('btn1');

	button.onclick = function buttonClicked()  {

		if(button.className=="off")  {
			button.className="on";
			oscOn ();
		}

		else if(button.className=="on")  {
			button.className="off";
			oscillator.disconnect();
		}
	}
};

buttonClickResult();

var oscOn = function(){

	window.AudioContext = window.AudioContext || window.webkitAudioContext;
	var context = new AudioContext();
	var gainNode = context.createGain ? context.createGain() : context.createGainNode();

	//context = new window.AudioContext();
	oscillator = context.createOscillator(),
			oscillator.type ='sine';

	oscillator.frequency.value = document.getElementById("fIn").value;
	//gainNode = createGainNode();
	oscillator.connect(gainNode);
	gainNode.connect(context.destination);
	gainNode.gain.value = 1;
	oscillator.start(0);
};
<p class="texts">Frekvence [Hz]</p>
<input type="range" id="fIn" min="20" max="20000" step="100" value="1234" oninput="show()" />
<span id="fOut"></span><br>
<input class="off" type="button" id="btn1" value="Start / Stop" />