Thursday, January 14, 2016

Firefox and Chrome Extensions and Automatic Updates

https://developer.mozilla.org/en-US/docs/Extension_Versioning,_Update_and_Compatibility
https://developer.mozilla.org/en-US/Add-ons/Distribution
https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/jpm
C:\Users\sizu\AppData\Roaming\npm\node_modules\jpm\bin\jpm
https://addons.mozilla.org/en-US/developers/addon/api/key/

TOPIC 1 - XPI SIGNATURE CREATION

To digitally sign the Firefox extension, you will need to get some Firefox credentials: JWT issuer, JWT secret.  These can be received after signing up by...

https://addons.mozilla.org/en-US/firefox/users/login?to=/en-US/developers/addon/api/key/ Tools->Manage API Keys->Generate New Credentials (JWT issuer, JWT secret)

 To create the .xpi file (extension file), you can do so with the jpm tool.  You should first download NPM, which you can use in Git Bash (needs to be downloaded too).

STEP 1: Then, you can run 'npm install jpm --global' in Git Bash.

STEP 2: After, you may create a package.json file using 'jpm init'.  After this is created, you should add additional fields beyond title, name, etc.  I added an id (@my_izu_extension), homepage, icon and main (picked a random js file in my content folder).

ERROR 1: I had an error with "Using existing install.rdf", since I had manually created this.  I just moved this into a backup folder after copying its contents to the package.json file, in the appropriate format.

ERROR 2: I had an Invalid addon ID.  You can use a GUID or any string with '@'.  I chose the later and used the ID '@my_izu_extension'.

STEP 3: Run 'jpm sign --api-key ${JWTissuer} --api-secret ${JWT secret}'.

Note: Here replace the ${xxx} with the credentials from the Firefox site (https://addons.mozilla.org/en-US/developers/addon/api/key/)

TOPIC 2 - AUTOMATIC UPDATES FOR FIREFOX EXTENSION

STEP 1: Firefox Updates over http.  Download McCoy from https://developer.mozilla.org/en-US/docs/Mozilla/Projects/McCoy.  Keys->Create New Key.  Right Click New Key->Copy Public Key.

STEP 2: This goes into the Firefox install.rdf file as updateKey. (put this in package JSON as updateKey, right along with id, title, name, etc).

Note: If using an install.rdf file, this can be done automatically with Extension->Add Key to Install Manifest and finding install.rdf file.

STEP 3:

To create an FirefoxUpdates.rdf file by copying it from here:
https://developer.mozilla.org/en-US/docs/Extension_Versioning,_Update_and_Compatibility

Delete the first <RDF:li> tag since you will use the second one which since the updateLink will be over http.  Change the id to match yours (mine was '@my_izu_extension').

Add an updateLink and updateInfoURL (these will need to be hosted somewhere).

You can generate the updateHash with openssl as follows 'openssl dgst -sha256 @my_izu_extension.xpi > updateHash.txt'

STEP 4:

This will run openssl and create a hash in the file updateHash.txt.  Something like this...

SHA256(my_izu_extension.xpi)= 2aefcd04c56f060bcfc53acfe96a87af120ed05933ab7969c91642847aa445df

Copy the hash and add it to the updateHash field but add the prefix 'sha256:'.  Something like this...

<em:updateHash>sha256:2aefcd04c56f060bcfc53acfe96a87af120ed05933ab7969c91642847aa445df</em:updateHash>

STEP 5: Then, add the updateHash into the FirefoxUpdates.rdf file by Update->Sign Update Manifest.

STEP 6: Upload the new @my_izu_extension.xpi file and FirefoxUpdates.rdf file appropriately.

RECAP.  Here's my setup.  I have a package.json with a my updateURL (pointing to where I will store the FirefoxUpdates.rdf file) and updateKey (generated by McCoy).  After adding these, I use jpm to create the @my_izu_extension.xpi file.

I create/modify the update.rdf file to include updateLink (pointing to where I will store the .xpi file).  I create a hash of the @my_izu_extension.xpi file (using openssl), then modify the updateHash field in FirefoxUpdates.rdf.  Finally, I digitally sign the FirefoxUpdates.rdf file using McCoy which adds the digital signature.

Last, I upload both the @my_izu_extension.xpi file and the FirefoxUpdates.rdf file to their appropriate locations.  I host them both in the same folder, both hosted by a Tomcat Server.

TOPIC 3 - AUTOMATIC UPDATES FOR GOOGLE CHROME EXTENSION

STEP 1: Modify the manifest.json file to add an update_url field right along side the name, description, etc.

STEP 2: Create an update.xml file like the one shown here: https://developer.chrome.com/extensions/autoupdate

I get the app id by using the chrome://extensions page, with Developer mode checked and use 'Load unpacked extension' which loads the extension and gives me the ID (aka appID).

STEP 3: Upload the update.xml file to where the update_url points.

Tuesday, January 12, 2016

Running Javascript in Firefox and Google Chrome

Suppose I want to run the printHelloWorldError function from this code in Firefox or Google Chrome. There are several ways to do it.

This code will add a div tag to the body tag of the page with the message 'Hello World'.

var err=function(e){
  var s=e.description;
  if(!s){
    s=String(e);
  }
  var d=DocumentFunction().createElement("div");
  d.id="print_err";
  d.innerHTML=s;
  d.style.color="red";
  DocumentFunction().body.appendChild(d);
};
var DocumentFunction;
var printHelloWorldError=function(){
  DocumentFunction = function() {
    return document;
  };
  err('HelloWorld');
};

Option 1 - From Firefox/Google Chrome Console

Edit the code above to add a line with this at the end: 'printHelloWorldError();' (don't include the single quotes).  Right click any page, Inspect (the element), Find the Console.  Paste the modified code in the console and hit Enter.  You should see the words 'Hello World' at the bottom of the page.

Option 2 - From the Firefox/Google Chrome Browser

Edit the code above to add a line with this at the beginning: 'javascript:' and this at the end 'printHelloWorldError();'.  Add it to Notepadd++.  Highlight the code and either drag it onto the Firefox address bar or right above the Google Chrome tab.

Option 3 - From the Firefox/Google Chrome Bookmark

If you drag and drop the edited code (with 'javascript:' at the beginning and 'printHelloWorldError();' at the end) into the Firefox address bar from Notepad++, it will reformat the Notepadd++ code into a single line like this:

javascript:var err=function(e){  var s=e.description;  if(!s){    s=String(e);  }  var d=DocumentFunction().createElement("div");  d.id="print_err";  d.innerHTML=s;  d.style.color="red";  DocumentFunction().body.appendChild(d);};var DocumentFunction;var printHelloWorldError=function(){  DocumentFunction = function() {    return document;  };  err('Hello World');};printHelloWorldError();

You can right click the Firefox Brower, show the Bookmark Toolbar, create a New Bookmark with the name 'Print Error' and for the location enter the above code.  Then, anytime you hit this bookmark, the code will execute.

In Google Chrome, Add a new bookmark by using 'Bookmark this page' from the hamburger menu.  Then, edit the bookmark and change the url to the code above (condensed one liner code with javascript: to indicate to run javascript code and printHelloWorldError(); to actually call the function).

Option 4a - From a Right Click Menu added through a Firefox Extension

Create an install.rdf file.

For other options like hompageURL, optionsURL, aboutURL, iconURL (ie em:iconURL="chrome://mypackage/content/myicon.png") which use the chrome.manifest file, see developer.mozilla.org

<?xml version="1.0"?>
<RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
         xmlns:NC="http://home.netscape.com/NC-rdf#"
         xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <RDF:Description RDF:about="urn:mozilla:install-manifest"
                   em:id="scottizu@gmail.com"
                   em:version="0.1"
                   em:name="Print Error"
                   em:unpack="true"
                   em:description="Prints an error on the page."
                   em:creator="scottizu">
    <em:targetApplication RDF:resource="rdf:#$RI.6J3"/>
  </RDF:Description>
    <RDF:Description RDF:about="rdf:#$RI.6J3"
                   em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
                   em:minVersion="1.5"
                   em:maxVersion="*.*" />
</RDF:RDF>


Note: The ID needs to either be an e-mail address or a GUID.  See link above for more details.

Create a chrome.manifest file.

content mypackage mycontent/ contentaccessible=yes
overlay chrome://browser/content/browser.xul chrome://mypackage/content/rightClickMenuForFirefox.xul

Create a folder called mycontent.  In it, create a file called rightClickMenuForFirefox.xul

<?xml version="1.0"?>
<overlay id="myoverlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
    <script type="application/x-javascript" src="chrome://mypackage/content/printError.js"/>
    
    // This is for the right click menu.
    <popup id="contentAreaContextMenu">
        <menuitem id="printError" label="Print Error" insertafter="context-stop" oncommand="printHelloWorldErrorForRightClick();"/>
    </popup>
</overlay>


Modify the printError.js file to add a method printHelloWorldErrorForRightClick.  The challenge in the right click menu for Firefox and Chrome is getting access to the document for the page.  This is why there is a function named DocumentFunction whose job is to return the document for the page.  This way, we can see the change on the web page we are looking at.


var err=function(e){
  var s=e.description;
  if(!s){
    s=String(e);
  }
  var d=DocumentFunction().createElement("div");
  d.id="print_err";
  d.innerHTML=s;
  d.style.color="red";
  DocumentFunction().body.appendChild(d);
};
var DocumentFunction;
var printHelloWorldError=function(){
  DocumentFunction = function() {
    return document;
  };
  err('Hello World');
};
var printHelloWorldErrorForRightClick=function(){
  DocumentFunction = function() {
    return gContextMenu.target.ownerDocument;
  };
  err('Hello World (RC)');
};

Here is the file structure.

- install.rdf
- chrome.manifest
- mycontent
   - rightClickMenuForFirefox.xul
   - printError.js

Highlight, install.rdf, chrome.manifest, mycontent, right click, send to, Compressed (zipped) folder.  Rename the new file as RightClickMenuForFirefox.xpi.  Go to Firefox 'about:config', 'I'll be careful, I promise', search for xpinstall.signatures.required, set to false so the new extension won't need signing.  Go to Firefox address bar and type 'about:addons', click Extensions and drag the file RightClickMenuForFirefox.xpi on this page.  Firefox will install this unsigned Extension, restart.  From there, you should be able to right click any page and select 'Print Error'.

There are many other things that you can do with the Firefox Extension such as adding an icon, adding a skin, etc.

You can also configure menus as well as menu items.  Just add something like this with appropriate closing menu and menupopup closing tags.

 <menu id="mymenu" label="Error Menu" insertafter="context-stop">            
            <menupopup>
                                   
                    <menu id="Error Sub Menu" label="Print Error Menu">
                        <menupopup>
                            <menuitem id="printError1" label="Print Error 1" oncommand="printHelloWorldErrorForRightClick();"/>
                            <menuitem id="printError2" label="Print Error 2" oncommand="printHelloWorldErrorForRightClick2();"/>

Option 4b - From a Right Click Menu added through a Google Chrome Extension

In the mycontent folder, create a file called manifest.json

Note: I debated whether to store this in the same directory as install.rdf, but the Chrome packager uses a folder, which in this case will be mycontent, so that the .crx file created will be at the same level as install.rdf.  This is unfortunate and the only difference is that the scripts value would be mycontent/rightClickMenuForGoogleChrome.js instead of rightClickMenuForGoogleChrome.js and execute script command would have to have mycontent/printError.js instead of printError.js if the manifest.json was up one level.

{
  "manifest_version": 2,
  "name""Print Error",
  "description""Prints an error on the page.",
  "version""0.1",
  "minimum_chrome_version""38",
  "permissions": [
    "contextMenus"
    "tabs",
    "http://*/*", 
    "https://*/*" ],

  "background": {
    "scripts": [
      "rightClickMenuForGoogleChrome.js"
    ]
  }
}


Create a file rightClickMenuForGoogleChrome.js

printErrorMenu = function(info, tab){
  chrome.tabs.executeScript(tab.id, {file:"printError.js"}, function() {
    chrome.tabs.executeScript(tab.id, {code:"printHelloWorldError();"});
  });
};

chrome.contextMenus.create({
  id: 'printError',
  title: "Print Error",
  contexts:["all"],
  onclick: printErrorMenu
});

Here is the file structure.
- mycontent
   - rightClickMenuForGoogleChrome.js
   - printError.js
   - manifest.json

Go to Google Chrome, in address bar type 'chrome://extensions', select Developer mode, Load unpacked extension, select the mycontent folder.

You can also package with the Pack extension (Developer mode must be checked).  Browse to mycontent folder as extension root directory (leave private key field empty).  This will create a .crx file and .pem file.  The .pem file is a private key file but is not needed if the field was left empty.  Later, you can drag and drop this .crx file directly onto the 'chrome://extensions' page.

You can also add other menu options to run more code.  Just make sure the appropriate onclick methods are defined.

chrome.contextMenus.create({
  id: 'parentMenu',
  title: "Error Menu",
  contexts:["all"]
});
chrome.contextMenus.create({
  id: 'printError1',
  parentId: 'parentMenu',
  title: "Print Error 1",
  contexts:["all"],
  onclick: printErrorMenu
});
chrome.contextMenus.create({
  id: 'printError2',
  parentId: 'parentMenu',
  title: "Print Error 2",
  contexts:["all"],
  onclick: printErrorMenu2
});

Sunday, January 3, 2016

Field Programmable Gate Arrays and Other Space Tech Initiatives

I am reading the book "Elon Musk" a biography and several things hit me well. One is that our industrial might has long since been gone from the 1940's. As such, I went to New Mexico attracted to strengthening that industrial might.

Also, our talented engineers are focused rather than solving world problems, on making money, often drawn to software and financial industries.

Here are some posting based on reconfiguring satellites in space, based on small payloads rather than large payloads.

Unfortunately, my experience with the industry is that a person could wait 7 years to launch their work, and their work might be part of phase 12 of 17. If phase 1, failed or the launch failed, that person would have to wait another 7 years for a next launch. Elon Musk seems to be determined to bring the agility of Silicon Valley to the aerospace industry. A noble quest.

I also saw a large amount of fluff, with no substantial technology behind it, which was a turn off to this industry. Real break throughs and transparency are important to me.

Abstract
Implementing Data Reduction Techniques in Recon…gurable Computing Platforms
Orbital Mechanics
Polarization

As far as solar technologies, while at ITT, in 2008, I worked with peers to create a proposal for a Broad Agency Announcement (BAA). We created a satellite design exploring capabilities of hybrid power systems involving solar power and electromagnetic tethers. We proposed methods for propelling the satellite using electromagenetic and momentum tether configurations to avoid the need for rocket fuel.

Real Time Visualization of Raw Sound from Microphone Input using HTML5

From www.smartjava.org ...

In order to use the webkitGetUserMedia method, your html code needs to be deployed on a server. That means, you can't just open the html in Google Chrome. This is unfortunate. However, you can deploy onto a server doing these three steps.


1. Install Tomcat 7 - http://mirror.symnds.com/software/Apache/tomcat/tomcat-7/v7.0.54/bin/apache-tomcat-7.0.54.exe
2. Go to the Task Manager, Services Tab, Services and start Tomcat
3. Open http://localhost:8080 in Chrome

You should see the index.jsp page that was installed with Tomcat. This would normally be in the "C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT" directory.

Create and html file named volume.html with the following contents:

<html>
<head>

<script type="text/javascript">

function canvasDrawLine(oPosX, oPosY, fPosX, fPosY) {
    var ctx = getCanvas().getContext('2d');
    ctx.beginPath();
    ctx.moveTo(oPosX, oPosY);
    ctx.lineTo(fPosX, fPosY);
    ctx.stroke();
}

function canvasDrawSquare(ulPosX, ulPosY, lrPosX, lrPosY) {
    canvasDrawLine(ulPosX, ulPosY, ulPosX, lrPosY);
    canvasDrawLine(ulPosX, lrPosY, lrPosX, lrPosY);
    canvasDrawLine(lrPosX, lrPosY, lrPosX, ulPosY);
    canvasDrawLine(lrPosX, ulPosY, ulPosX, ulPosY);


function canvasInitialize(width, height) {
    // Set canvas parameters
    getCanvas().width = width;
    getCanvas().height = height;

    // Outline
    getCanvas().getContext('2d').clearRect(0,0,width,height);
    canvasDrawSquare(0,0,width,height);
}

function getAverageVolume(array) {
    var values = 0; 
    // get all the frequency amplitudes
    for (var i = 0; i < array.length; i++) {
        values += array[i];
    }
    return values / (array.length);
}

function onSuccess(stream) {
    var context = new webkitAudioContext();
    var mediaStreamSource = context.createMediaStreamSource(stream);
    
    var analyser = context.createAnalyser();
    analyser.smoothingTimeConstant = 0.3;
    analyser.fftSize = 1024;
    
    var javascriptNode = context.createScriptProcessor(2048, 1, 1);
    
    javascriptNode.onaudioprocess = function(e) {
        //var sample = e.inputBuffer.getChannelData(0);

        // get the average, bincount is fftsize / 2
        var array =  new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        
        // calculate average
        var average = getAverageVolume(array)
        
        // print value out
        log(average);
        
        // draw green bar
        getCanvas().getContext('2d').strokeStyle='#000000';
        canvasInitialize(200,200);
        getCanvas().getContext('2d').strokeStyle='#00ff00';
        canvasDrawSquare(10, 150, 20, 150-average*5);
    };
    
    // stream -> mediaSource -> analyser -> javascriptNode -> destination
    mediaStreamSource.connect(analyser);
    analyser.connect(javascriptNode);
    javascriptNode.connect(context.destination);
}

function onError() {
    alert('Error');
}

function log(logVal) {
    getLog().innerHTML = logVal + '\n<br>';
}

function getCanvas() {
    return document.getElementById('mycanvas');
}    
 
function getLog() {
    return document.getElementById('mylog');
}
  
function documentReady() {
    if(navigator.getUserMedia) {
        navigator.getUserMedia({video: false, audio: true}, onSuccess, onError);
    } else if(navigator.webkitGetUserMedia) {
        navigator.webkitGetUserMedia({video: false, audio: true}, onSuccess, onError);
    }
}
</script>
</head>

<body onload="documentReady();">
   <canvas id="mycanvas"></canvas>
   <div id="mylog"></div>
</body>
</html>


Without stopping Tomcat, copy this file into the ROOT directory, specified above and open the http://localhost:8080/volume.html in Google Chrome. You should see a message that allows you to access the Microphone. Then you should see a green box along with changing numbers that indicate the volume.

This post was reposted from scottizu.wordpress.com, originally written on June 23rd, 2014.

Real Time Visualization of a Spectrogram

From www.smartjava.org.

This code needs to be added to a Tomcat server to work. This allows the microphone in Chrome to be connected. See Real Time Visualization of Raw Sound from Microphone Input using HTML5.

Some notes on this, that not all frequencies are shown in this. Also, the shift method, copies what is on the canvas and then pastes it a few pixels over, based on the shift parameters.

<html>
<head>
<script type="text/javascript">

function interpolate(x, x0, xf, y0, yf) {
    // (x - x0)/(xf - x0) = (y - y0)/(yf - y0)
    // y = ( (x-x0)/(xf-x0) ) * (yf-y0) + y0
    return Math.floor( ( (x-x0)/(xf-x0) ) * (yf-y0) + y0 );
}

// colors:['#000000', '#ff0000', '#ffff00', '#ffffff']
// positions:[0, 64-1, 192-1, 255]
// 0 = parseInt('00', 16), 256-1 = parseInt('ff', 16)
function findColor(val) {
    var r, rDec, g, gDec, b, bDec;
    if(val < 64) {
        rDec = interpolate(val, 0, 64-1, 0, 256-1);
        r = rDec.toString(16);
        g = '00';
        b = '00';
    } else if (val < 192) {
        r = 'ff';
        gDec = interpolate(val, 64, 192-1, 0, 256-1); 
        g = gDec.toString(16);
        b = '00';
    } else {
        r = 'ff';
        g = 'ff';
        bDec = interpolate(val, 192, 256-1, 0, 256-1); 
        b = bDec.toString(16);
    }
    return '#'+r+g+b;
}

function canvasFillCoordinate(leftX, topY, val) {
    getCanvas().getContext('2d').fillStyle = findColor(val);
    getCanvas().getContext('2d').fillRect(leftX, topY, 1, 1);
}

function canvasInitialize(width, height) {
    getCanvas().getContext('2d').strokeStyle='#000000';
    
    // Set canvas parameters
    getCanvas().width = width;
    getCanvas().height = height;

    // Outline
    getCanvas().getContext('2d').clearRect(0,0,width,height);
    getCanvas().getContext('2d').rect(0,0,width,height);
    getCanvas().getContext('2d').stroke();
}

function onSuccess(stream) {
    // stream -> mediaSource -> javascriptNode -> destination
    var context = new webkitAudioContext();
    var mediaStreamSource = context.createMediaStreamSource(stream);
    var analyser = context.createAnalyser();
    analyser.smoothingTimeConstant = 0.3;
    analyser.fftSize = 2048;
    var javascriptNode = context.createScriptProcessor(2048, 1, 1);
    mediaStreamSource.connect(analyser);
    analyser.connect(javascriptNode);
    javascriptNode.connect(context.destination);
    
    javascriptNode.onaudioprocess = createProcessBuffer(analyser);
}

function createProcessBuffer(analyser) {
    canvasInitialize(1024,1024);
    var time = 0;
    return function processBuffer() {
        time = time + 1;
        if(time > 1000) {
            canvasInitialize(1024,1024);
            time = 0;
        }
    
        var fftData =  new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(fftData);
    
        var average = 0;
        var min = 200;
        var max = 50;
        for(var freq=0; freq<fftData.length; freq++) {
            var sample = fftData[freq];
            canvasFillCoordinate(time, freq, sample);
            average = average + sample;
        }
        average = average/fftData.length;
        getLog().innerHTML = 'FFT Length:'+fftData.length + ' Average:' + average + '\n<br>';
    };
}

function onError() {
    alert('Error');
}

function getLog() {
    return document.getElementById('mylog');
}

function getCanvas() {
    return document.getElementById('mycanvas');
}    
  
function documentReady() {
    var dataObject = {video: false, audio: true}; // dataObject.video, dataObject.audio
    if(navigator.getUserMedia) {
        navigator.getUserMedia(dataObject, onSuccess, onError);
    } else if(navigator.webkitGetUserMedia) {
        navigator.webkitGetUserMedia(dataObject, onSuccess, onError);
    }
}
</script>
</head>
<body onload="documentReady();">
   <canvas id="mycanvas"></canvas>
   <div id="mylog"></div>
</body>
</html>


This post was reposted from scottizu.wordpress.com, originally written on June 24th, 2014.

I was curious to see if this code still worked and how quickly I could get up and running with this after over a year. It turns out the code froze after drawing the spectrogram for a few seconds, after I started making chirping sounds to see the effect on the real time visualization. A good sign was that I was able to get up and running fairly quickly. I have updated the code and it seems to work better. Here's what I did.

To run the Tomcat 7.0 server, I right clicked the task bar, Task Manager, Services Tab, Hit the Services Button, found Apache Tomcat 7.0, selected it, clicked start (this all worked because I had previously installed Apache Tomcat on my machine).

To add the file, I created a new file, "spectrogram.html", edited the file to add the code above, then dropped it into the folder "C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT" which is Tomcat 7.0's root directory.

I opened Google Chrome and went to http://localhost:8080/spectrogram.html.

Related to A Tutorial for Real Time Pitch Detection.

Eigenvalue Estimates and Sampling for Time-Frequency Localization Operators

Here is a document that discusses the relationship between the fourier transform and the discrete fourier transform. This can be used to help improve methods for pitch detection: Eigenvalue Estimates and Sampling for Time-Frequency Localization Operators

This document describes a pitch detection algorithm created for Tartini: A Smarter Way to Find Pitch

Download Post Script Viewer: I think I used GPL Ghostscript (gs\gs9.05\bin\gswin32.exe) which will help create PDFs from LaTex.

Download MiKTeX: miktex.org
Installer: mirrors.ctan.org
Download TeXnic Center: www.texniccenter.org
32-bit Installer: sourceforge.net

This post was reposted from , originally written on June 26th, 2014.

A Tutorial for Real Time Pitch Detection with HTML5

Over the past year, I have been working on analyzing music. Some notes will be posted here for future work and reference.

The first document, is in PDF format and is a tutorial for people to find their way into signal processing. It is meant to allow HTML5 coding to utilize Google Chrome for real time pitch detection.

Unfortunately, the work is incomplete. The last 3 pages (27-29) are just notes. I meant to include two additional proofs regarding the fact that the circular Auto Correlation function can be obtained by taking the Fourier Transform, taking the square root of its magnitude (also pointwise multiplication by the complex conjugate) and taking the inverse Fourier Transform. While this produces edge effects, one may also calculate the Auto Correlation function, which can be obtained by zero padding the signal and then taking the circular Auto Correlation function for the zero padded signal.

PitchDetection

Also, an interesting look at the 50's Progression on the piano, and a short song I wrote which looks at various harmonies played above the bass progression.

My_Song

Ideally, this work could morph into real time pitch and beat detection.

This post was reposted from scottizu.wordpress.com, originally written on August 29th, 2014.