Est-il possible de générer un flux sonore constant avec javascript/html5? Par exemple, pour générer une onde sinusoïdale perpétuelle, j'aurais une fonction de rappel, qui serait appelée chaque fois que le tampon de sortie est sur le point de devenir vide:
function getSampleAt(timestep)
{
return Math.sin(timestep);
}
(L'idée est de l'utiliser pour faire un synthé interactif. Je ne sais pas à l'avance combien de temps une touche sera enfoncée, donc je ne peux pas utiliser un tampon de longueur fixe)
L'audio soutenu génératif multi-navigateur utilisant JavaScript et l'élément audio
n'est actuellement pas possible, comme Steven Wittens notes dans un article de blog sur la création d'un synthétiseur JavaScript:
"... il n'y a aucun moyen de mettre en file d'attente des morceaux audio synthétisés pour une lecture fluide".
Web Audio API a été conçu pour faciliter la synthèse audio JavaScript. Le Mozilla Developer Network a un générateur de tonalité basé sur le Web qui fonctionne dans Firefox 4+ [ démo 1 ]. Ajoutez ces deux lignes à ce code et vous disposez d'un synthétiseur fonctionnel avec un son génératif soutenu lors d'une pression de touche [ démo 2 - ne fonctionne que dans Firefox 4, cliquez d'abord sur la zone "Résultats", puis appuyez sur n'importe quelle touche]:
window.onkeydown = start;
window.onkeyup = stop;
La BBC page sur l'API Web Audio mérite également d'être revue. Malheureusement, la prise en charge de l'API Web Audio ne s'étend pas encore aux autres navigateurs.
Pour créer un synthé multi-navigateur à l'heure actuelle, vous devrez probablement vous rabattre sur l'audio préenregistré en:
audio
séparés et en les démarrant et en les arrêtant lors d'une pression sur une touche.Vous pouvez désormais utiliser Web Audio API dans la plupart des navigateurs ( sauf IE et Opera Mini ) .
Essayez ce code:
// 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
Si vous souhaitez réduire le volume, vous pouvez faire quelque chose comme ceci:
var context = new webkitAudioContext();
var osc = context.createOscillator();
var vol = context.createGain();
vol.gain.value = 0.1; // from 0 to 1, 1 full volume, 0 is muted
osc.connect(vol); // connect osc to vol
vol.connect(context.destination); // connect vol to context destination
osc.start(context.currentTime + 3); // start it three seconds from now
J'ai tiré la majeure partie de cela de l'expérimentation du chrome en lisant le Web Audio API Working Draft , que j'ai trouvé sur le lien de @brainjam.
J'espère que ça aide. Enfin, il est très utile d'inspecter les différents objets dans l'inspecteur chrome (ctrl-shift-i).
L'API Web Audio arrive sur Chrome. Voir http://googlechrome.github.io/web-audio-samples/samples/audio/index.html
Suivez les instructions de la section "Mise en route", puis découvrez les démos très impressionnantes.
Mise à jour (2017): c'est maintenant une interface beaucoup plus mature. L'API est documentée à https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
Sûr! Vous pouvez utiliser le synthétiseur de sons dans cette démo:
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>
S'amuser!
J'ai obtenu la solution de Houshalter ici: Comment puis-je faire un bip Javascript?
Vous pouvez cloner et modifier le code ici: Démo du synthétiseur de tonalité sur JS Bin
Vous pouvez générer un fichier wav-e à la volée et le lire ( 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()
Voici la visualisation
function getSampleAt(t,DUR,SPS)
{
return 0.5+Math.sin(15*t)/(1+t*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);
}
function draw(fun, DUR=1, NCH=1, SPS=44100, BPS=1) {
time.innerHTML=DUR+'s';
time.setAttribute('x',DUR-0.3);
svgCh.setAttribute('viewBox',`0 0 ${DUR} 1`);
let p='', n=100; // n how many points to ommit
for (let i = 0; i < DUR*SPS/n; i++) p+= ` ${DUR*(n*i/SPS)/DUR}, ${1-fun(n*i/SPS, DUR,SPS)}`;
chart.setAttribute('points', p);
}
function frame() {
let t=WAV.currentTime;
point.setAttribute('cx',t)
point.setAttribute('cy',1-getSampleAt(t))
window.requestAnimationFrame(frame);
}
function changeStart(e) {
var r = e.target.getBoundingClientRect();
var x = e.clientX - r.left;
WAV.currentTime = dur*x/r.width;
WAV.play()
}
var dur=5; // seconds
var WAV = new Audio(genWAVUrl(getSampleAt,dur));
draw(getSampleAt,dur);
frame();
.chart { border: 1px dashed #ccc; }
.axis { font-size: 0.2px}
audio { outline: none; }
Click at blue line (make volume to max):
<svg class="chart" id="svgCh" onclick="changeStart(event)">
<circle cx="0" cy="-1" r="0.05" style="fill: rgba(255,0,0,1)" id="point"></circle>
<polyline id="chart" fill="none" stroke="#0074d9" stroke-width="0.01" points=""/>
<text x="0.03" y="0.9" class="axis">0</text>
<text x="0.03" y="0.2" class="axis">1</text>
<text x="4.8" y="0.9" class="axis" id="time"></text>
</svg><br>
Ce n'est pas une vraie réponse à votre question car vous avez demandé une solution JavaScript, mais vous pouvez utiliser ActionScript. Il devrait fonctionner sur tous les principaux navigateurs.
Vous pouvez appeler des fonctions ActionScript à partir de JavaScript.
De cette façon, vous pouvez envelopper les fonctions de génération de sons ActionScript et en faire une implémentation JavaScript. Utilisez simplement Adobe Flex pour créer un petit swf, puis utilisez-le comme backend pour votre code JavaScript.
C'est ce que j'ai recherché pour toujours et à la fin j'ai réussi à le faire moi-même comme je le voulais. Peut-être que vous l'aimerez aussi. Curseur simple avec fréquence et Push on/off:
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" />