Is there a way to detect audio frequency in HTML 5 web audio API? - html

I would like to know is there a way we can detect audio frequency from microphone in html 5 web audio. I wish to make an online guitar tuner, and I need to have the audio frequency in hertz, from the sound input. I've seen some EQ and filters effects, but I didn't see anything about frequency recognition.
EDIT:
I found this: http://www.smartjava.org/content/exploring-html5-web-audio-visualizing-sound
The 2nd point (analyser node) is really interesting. I seen his source code, but I can't figure how to connect the analyser to the microphone input.
He calls a playSound() function when the mp3 file starts to play, and there he draws his canvas. But I do not have a playSound() like function...

I wrote a web audio library which, among other things, can detect frequency from mic input. Check it out at https://github.com/rserota/wad#pitch-detection
var voice = new Wad({source : 'mic' });
var tuner = new Wad.Poly();
tuner.add(voice);
voice.play();
tuner.updatePitch() // The tuner is now calculating the pitch and note name of its input 60 times per second. These values are stored in tuner.pitch and tuner.noteName.
var logPitch = function(){
console.log(tuner.pitch, tuner.noteName)
requestAnimationFrame(logPitch)
};
logPitch();
// If you sing into your microphone, your pitch will be logged to the console in real time.
tuner.stopUpdatingPitch(); // Stop calculating the pitch if you don't need to know it anymore.

You should be able to use BiquadFilterNode.
Example code from the link:
var audioCtx = new AudioContext();
var biquadFilter = audioCtx.createBiquadFilter();
biquadfilter.getFrequencyResponse(myFrequencyArray,magResponseOutput,phaseResponseOutput);

You can use the following code to get the frequencies from the mic.
navigator.mediaDevices.getUserMedia({audio:true}).then(function(localStream){
var audioContext = new(window.AudioContext || window.webkitAudioContext)();
var input = audioContext.createMediaStreamSource(localStream);
var analyser = audioContext.createAnalyser();
var scriptProcessor = audioContext.createScriptProcessor();
// Some analyser setup
analyser.smoothingTimeConstant = 0;
analyser.fftSize = 64;
input.connect(analyser);
analyser.connect(scriptProcessor);
scriptProcessor.connect(audioContext.destination);
var getAverageVolume = function( array){
var length = array.length;
var values = 0;
var i = 0;
for (; i < length; i++) {
values += array[i];
}
return values / length;
};
var onAudio = function(){
var tempArray = new window.Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(tempArray);
var latestFrequency = (getAverageVolume(tempArray));
//use latestFrequency
};
scriptProcessor.onaudioprocess = onAudio;
})
.catch(function(){
//Handle error
});

Related

Play two videos simultaneously with sync in AS3

I am busy with a project where two videos have to play on top of each other.
Like the one in the following site, http://kindnessday.sg/home#/kindness/home
Because of the large filesize I cannot embed the videos in the swf. It will become too large. Therefore the video's must be loaded thro' webstream link. But First video plays before the second video and causing the videos unsynced.
Is there a way to play both video at the same time?
var stream = 'http://mydomain/clip1.mp4'
var stream1 = 'https://mydomain/clip2.mp4'
var http_stream:URLStream = null
var http_stream1:URLStream = null
var video:Video = new Video() // the video is used only to ensure that stream is playing
var video1:Video = new Video() // the video is used only to ensure that stream is playing
addChild(video1)
addChild(video)
var nc:NetConnection = new NetConnection()
nc.connect(null)
var ns:NetStream = new NetStream(nc)
ns.client = new Object()
ns.client.onMetaData = function(e){}
ns.play(null)
var ns1:NetStream = new NetStream(nc)
ns1.client = new Object()
ns1.client.onMetaData = function(e){}
ns1.play(null)
video.attachNetStream(ns)
video1.attachNetStream(ns1)
http_stream = new URLStream();
http_stream.addEventListener(ProgressEvent.PROGRESS, on_Progress)
http_stream.load(new URLRequest(stream))
http_stream1 = new URLStream();
//http_stream1.addEventListener(ProgressEvent.PROGRESS, on_Progress1)
http_stream1.load(new URLRequest(stream1))
function on_Progress(e:ProgressEvent):void {
var b:ByteArray = new ByteArray()
http_stream.readBytes(b, 0, http_stream.bytesAvailable)
ns.appendBytes(b)
var b1:ByteArray = new ByteArray()
http_stream1.readBytes(b1, 0, http_stream1.bytesAvailable)
ns1.appendBytes(b1)
if (ns.appendBytes(b)==ns1.appendBytes(b1)){
ns.play(stream);
ns1.play(stream1);
}
}
why not not check how much of each video has loaded and when you have enough amount (you decide) then you can run some function to play both netstreams...
var min_amount : int = 500000; //for 500 kb minimum
var check_if_ready : Boolean = true;
Also on progressEvent function of loading (URLloader or URLstream???)..
if ( check_if_ready == true )
{
if( myA_NetStream.bytesLoaded >= min_amount && myB_NetStream.bytesLoaded >= min_amount )
{
myA_NetStream.play(); myB_NetStream.play();
//reset since not needed on further progressEvents during this load
check_if_ready = false;
}
}
}
This should only play when both videos have loaded x-amount of bytes. Therefore you can be sure none starts before another)
For better synchronization control you should get into handling bytes in Flash/AS3 and using the AppendBytes method because then you can control playback on a frame-by-frame basis for both NetStreams.

Using present time of video to manage all video in Action Script 3.0

I would like to use present time of video to manage all video. For example, I have some cue points, I choose it and video is now playing from this cue point, and after 10 sec video goes to other part and everything depends on present time of video. I do not use it on web so my video isn't loading (I mean that property of VideoProgressEvent like bytesLoaded will not help me). Is it possible to do it in action script 3.0 ? Another question is if I can add some transitions between cue points.
import fl.video.*;
// Video component instance name
var flvControl:FLVPlayback = display;
var flvSource:String = "myMovie.flv";
// Set video
flvControl.source = flvSource;
var myTextFormat:TextFormat = new TextFormat();
myTextFormat.size = 20
btn1.setStyle("textFormat", myTextFormat);
btn2.setStyle("textFormat", myTextFormat);
btn3.setStyle("textFormat", myTextFormat);
btn4.setStyle("textFormat", myTextFormat);
display.autoPlay = false;
// Add seek to time code
function seekToTimeHandler1(event:MouseEvent):void
{
var sec:Number = 15;
flvControl.seek(sec);
}
btn1.addEventListener(MouseEvent.CLICK, seekToTimeHandler1);
// Add seek to time code
function seekToTimeHandler2(event:MouseEvent):void
{
var sec:Number = 61;
flvControl.seek(sec);
}
btn2.addEventListener(MouseEvent.CLICK, seekToTimeHandler2);
// Add seek to time code
function seekToTimeHandler3(event:MouseEvent):void
{
var sec:Number = 63;
flvControl.seek(sec);
}
btn3.addEventListener(MouseEvent.CLICK, seekToTimeHandler3);
// Add seek to time code
function seekToTimeHandler4(event:MouseEvent):void
{
var sec:Number = 80;
flvControl.seek(sec);
}
btn4.addEventListener(MouseEvent.CLICK, seekToTimeHandler4);

Filling in my own Web Audio Buffer is not working

I'm using Web Audio for various purposes and while samples loaded via URL and oscillators are working and playing properly, building a custom source buffer is not. I have tried to load my own AudioBuffer into an AudioBufferSourceNode using the code below and through the Chrome-NetBeans debugger I can see that it's loading the buffer with data and no errors are flagged, but when start is called, no sound is ever produced. Note that I'm just filling the buffer with noise, but I plan to fill it with my own custom wave data. I realize it's likely that I'm filling the buffer with the wrong data type, but I have been unable to find any documentation or examples regarding the proper way of doing it. Any help would be appreciated.
var audioContext = new (window.AudioContext || window.webkitAudioContext)();
var frameCount = 2000;
var sampleRate = 4000;
var myBuffer = audioContext.createBuffer(2, frameCount, sampleRate);
// FILL WITH WHITE NOISE
for (var i = 0; i < frameCount; i++) {
myBuffer[i] = Math.random() * 2 - 1;
}
sourceNode = audioContext.createBufferSource();
sourceNode.buffer = myBuffer;
sourceNode.connect(audioContext.destination);
sourceNode.start(0);
This will synth your noise inside a callback method which is called everytime you have rendered yet another BUFF_SIZE number of samples
var BUFF_SIZE = 2048; // spec allows, yet do not go below 1024
var audio_context = new AudioContext();
var gain_node = audio_context.createGain();
gain_node.connect( audio_context.destination );
var source_node = audio_context.createScriptProcessor(BUFF_SIZE, 1, 1);
source_node.onaudioprocess = (function() {
return function(event) {
var synth_buff = event.outputBuffer.getChannelData(0); // mono for now
// FILL WITH WHITE NOISE
for (var i = 0, buff_size = synth_buff.length; i < buff_size; i++) {
synth_buff[i] = Math.random() * 2 - 1;
}
};
}());
source_node.connect(gain_node);

XMP data encrypted on Canon EOD D1000

I have a question regarding encryption, once again this relates to reading serial numbers from the aux:SerialNumber namespace.
When I open my file in AS3 from photos of the Canon EOS D1000, it can't read this bit in the ByteArray var i:int = p.search('<x:xmpmeta xmlns:x="\'dobe:ns:meta/\''); because well its encrypted.
What makes this interesting is, if I open the file in Photoshop then save it and close it the XMP data is correct and my app can read it.
My question would be how would I decrypt the XMP data from within AS3? Is there a way to do it. Or another way to read it?
This is the method I use:
private function getXMP(ba:ByteArray):XML
{
var LP:ByteArray = new ByteArray();
var PACKET:ByteArray = new ByteArray();
var l:int;
ba.readBytes(LP, 2, 2);
//http://www.adobe.com/devnet/xmp.html read part 3: Storage in Files.
//that will explain the -2 -29 and other things you see here.
l = LP.readInt() - 2 -29;
ba.readBytes(PACKET, 33, l);
var p:String = trim(""+PACKET);
var i:int = p.search('<x:xmpmeta xmlns:x="adobe:ns:meta/"');
//Delete all in front of the XMP XML
p = p.substr(i);
//For some reason this left some rubbish in front, so I'll hardcode it out for now
var ar:Array = p.split('<');
var s:String = "";
var q:int;
var j:int = ar.length;
for(q=1;q<j;q++)
{
s += '<'+ar[q];
}
i = s.search('</x:xmpmeta>');
i += ('</x:xmpmeta>').length;
s = s.slice(0,i);
//Delete all behind the XMP XML
//trace(s);
return XML(s);
}

Play a random flv from a total of 5 flvs

I need your help with Actionscipt3.0. To be honest I am reall noob in flash. I am more a 3D Designer so not a lot of flash ;)
Currently I have to create a website where some videos should be played automatically.
When a User opens the URL and lands on the page, a random video of a total of 5 should be played. When the video is finished, it should chose another video of the total of 5 videos.
So an example: It should chose one video of 5 videos. Play it, then it should chose 1 video of 4 videos, then it should chose 1 video of 3 videos..and so on. And after all 5 are played, it should repeat the process.
I hope someone here can help me with that...What i have sofar is this..
var files:Array = [ "Sz01Puppet.flv", "Sz02Puppet.flv",
"Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv" ]; var
randomFiles:Array = [];
var i:int; for (i=0; i
randomFiles.push(files[Math.floor(Math.random() * files.length)]);
}
trace(randomFiles);
But its not working in any way..
Would be great if someone could help me out
Yup, you're nearly there.
Here's how the for loop should've been written:
var files:Array = [ "Sz01Puppet.flv", "Sz02Puppet.flv", "Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv" ]; var randomFiles:Array = [];
var i:int;
for(i = 0 ; i < files.length; i++) randomFiles.push(files[Math.floor(Math.random() * files.length)]);
trace(randomFiles);
Still, you're note removing items form the array, so you'll have duplicates.
Here's an an example:
var files:Array = [ "Sz01Puppet.flv", "Sz02Puppet.flv", "Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv" ];
var shuffledFiles:Array = shuffleArray(files);
//quick test
var testTimer:Timer = new Timer(1000);
testTimer.addEventListener(TimerEvent.TIMER,updateFile);
testTimer.start();
function updateFile(event:TimerEvent):void{
if(shuffledFiles.length == 0) shuffledFiles = shuffleArray(files);//all files played, repeat process
trace('play file',shuffledFiles[0]);
shuffledFiles.shift();
}
function shuffleArray(source:Array,clone:Boolean = true):Array {
var output:Array = [];
var input:Array = clone ? [].concat(source) : source;//clone ? preserve orignal items by making a copy for shuffling, or not
while(input.length) output.push(input.splice(int(Math.random() * input.length-1),1)[0]);
return output;
}
Goodluck
You could use the Array.sort() function to sort it randomly.
// random sort function
function shuffle(a:*, b:*):int
{
return int(Math.random() * 2) - 1;
}
var files:Array = ["Sz01Puppet.flv", "Sz02Puppet.flv", "Sz03Puppet.flv", "Sz04Puppet.flv", "Sz05Puppet.flv"];
var randomFiles:Array = files.sort(shuffle); // get a new instance of the array which is sorted
trace(randomFiles);
Here is one way to do it.