I have posted a code example that shows how to record audio from a microphone in a web browser using the Web Audio API.
Take a look a the demo and the code HERE
It turns out that the API does not support recording directly so you have to add consecutive samples of audio data to your own recording buffer. You need to grow the size of the buffer whenever you add a new sample. Once you have your recording you can use it as the source of a BufferSourceNode and play it back.
A collection of computer systems and programming tips that you may find useful.
Brought to you by Craic Computing LLC, a bioinformatics consulting company.
Tuesday, July 2, 2013
Friday, June 28, 2013
Vocabrio - a new way to learn a language
I am very pleased to announce the launch of Vocabrio - a new web service from Craic that helps you improve your vocabulary in a foreign language.
Vocabrio lets you read any web site in your target language and translate those words that are new to you. The words are added to your custom dictionary and you can test what you have learned with custom quizzes.
Unlike a general textbook, Vocabrio lets you build up a vocabulary of the words that are relevant to your interests, making it more useful than existing tools.
Vocabrio makes use of some amazing new web technologies.
You can listen to how any word is pronounced using Speech Synthesis and HTML5 Web Audio in your browser (no Flash or plugin required!)
You can test your own pronunciation using Web Audio and cutting edge Speech Recognition - all in your browser.
Vocabrio is free to use while it is in Beta release - over time it will shift to a paid subscription.
You can learn more and sign up for an account at http://vocabrio.com
Vocabrio lets you read any web site in your target language and translate those words that are new to you. The words are added to your custom dictionary and you can test what you have learned with custom quizzes.
Unlike a general textbook, Vocabrio lets you build up a vocabulary of the words that are relevant to your interests, making it more useful than existing tools.
Vocabrio makes use of some amazing new web technologies.
You can listen to how any word is pronounced using Speech Synthesis and HTML5 Web Audio in your browser (no Flash or plugin required!)
You can test your own pronunciation using Web Audio and cutting edge Speech Recognition - all in your browser.
Vocabrio is free to use while it is in Beta release - over time it will shift to a paid subscription.
You can learn more and sign up for an account at http://vocabrio.com
Wednesday, June 19, 2013
Example of Web Speech Recognition and Audio Capture
I'm doing a lot of work with the Web Audio API for both playing audio streams and capturing them from a user's microphone. I'm also working with the Speech Recognition component of the Web Speech API, as implemented by Google.
I wanted to combine both of these and so I've written up a simple example:
On this page you can speak and have your words transcribed via Google Speech Recognition and at the same time see the frequency spectrogram of your voice.
Both of these browser technologies offer tremendous potential for web developers. It is great fun experimenting with them, even before they are fully mature - and I am already using them in a new application Vocabrio, that helps you improve your vocabulary in a foreign language.
The page only works in the Google Chrome browser at the moment. The page and JavaScript is released under the MIT license.
I wanted to combine both of these and so I've written up a simple example:
On this page you can speak and have your words transcribed via Google Speech Recognition and at the same time see the frequency spectrogram of your voice.
Both of these browser technologies offer tremendous potential for web developers. It is great fun experimenting with them, even before they are fully mature - and I am already using them in a new application Vocabrio, that helps you improve your vocabulary in a foreign language.
The page only works in the Google Chrome browser at the moment. The page and JavaScript is released under the MIT license.
Labels:
google chrome,
speech recognition,
vocabrio,
web audio
Thursday, June 13, 2013
Migrating from Rails HABTM to has_many :through
I had a has_and_belongs_to_many (HABTM) association that I needed to convert to has_many through with an explicit model that contains additional columns.
In my example a User knows about many Words and each Word is known by many Users.
You can find many pages on the web about the differences. The consensus is that has_many :through is the way to go from the start - and after this process I agree.
Making the change in itself is not a big deal - drop the existing joining table 'users_words', create the new one, update the User and Word models and you're good to go.
Problem is that I already had data in the joining table...
And because the standard way of setting up a HABTM joining table does not include an id column, you can't just use that table or directly copy each record from it. Dang it...
Here were my steps - hopefully I got them all - don't skip any !
1: Backup your database and prevent users from accessing it
2: Do not touch any of the old associations, table, etc
3: Create the new table and model with a different name from the old joining table.
My HABTM table was users_words and my new table is user_work_links
4: Update the two models
My original association was this - do not change it yet !
The new association is this - NOTE the second line is commented out for now - VERY important !
5: Copy over the data from the old joining table with a rake task
You need to go through the existing associations one by one to get the ids for records in the two tables.
Here is my script:
6: Update the two models
Now you can comment out the old associations and uncomment the new ones
In the attr_accessible lists in the two models be sure to add :user_ids in the Word model and :word_ids in the User model. If your forget this it will silently fail to create the records
7: Test Test Test
You should be back up and running with the new model
8: Remove the old table
Finally create a migration that drops the old table and run it
Not too bad as long as you think it through before you start and don't rush the steps
In my example a User knows about many Words and each Word is known by many Users.
You can find many pages on the web about the differences. The consensus is that has_many :through is the way to go from the start - and after this process I agree.
Making the change in itself is not a big deal - drop the existing joining table 'users_words', create the new one, update the User and Word models and you're good to go.
Problem is that I already had data in the joining table...
And because the standard way of setting up a HABTM joining table does not include an id column, you can't just use that table or directly copy each record from it. Dang it...
Here were my steps - hopefully I got them all - don't skip any !
1: Backup your database and prevent users from accessing it
2: Do not touch any of the old associations, table, etc
3: Create the new table and model with a different name from the old joining table.
My HABTM table was users_words and my new table is user_work_links
4: Update the two models
My original association was this - do not change it yet !
has_and_belongs_to_many :words, :uniq => true
The new association is this - NOTE the second line is commented out for now - VERY important !
has_many :user_word_links, :dependent => :destroy
# has_many :words, :through => :user_word_links, :uniq => true
5: Copy over the data from the old joining table with a rake task
You need to go through the existing associations one by one to get the ids for records in the two tables.
Here is my script:
namespace :craic do
desc "move user word data"
task :move_user_word_data => :environment do
users = User.all
users.each do |user|
user.words.each do |word|
record = UserWordLink.new({ :user_id => user.id, :word_id => word.id })
record.save
end
end
end
end
6: Update the two models
Now you can comment out the old associations and uncomment the new ones
# has_and_belongs_to_many :words, :uniq => true
has_many :user_word_links, :dependent => :destroy
has_many :words, :through => :user_word_links, :uniq => true
In the attr_accessible lists in the two models be sure to add :user_ids in the Word model and :word_ids in the User model. If your forget this it will silently fail to create the records
7: Test Test Test
You should be back up and running with the new model
8: Remove the old table
Finally create a migration that drops the old table and run it
Not too bad as long as you think it through before you start and don't rush the steps
Friday, June 7, 2013
Unix command 'comm' for comparing files
I needed a simple way to compare two similar files and only output lines that were unique to the second file.
Sounded like a job for 'diff' but I was not finding the right options to give me what I needed. And then I stumbled across 'comm' - a standard UNIX command that I don't think I have ever used.
That does exactly what I needed. My two files look like this
File A
File A
A B D EFile B
A B C DI want the command to just output 'C' By default comm compares two files and produces 3 columns of text - lines that are only in file A, lines that are only in file B and lines that are in both. So with these two files I get:
$ comm tmp_A tmp_B
A
B
C
D
E
Ugly, and not what I want... But then you can suppress the output of one or more of these columns using -1, -2, -3 options and combinations of those. I want to suppress lines that are only in file A and those in common:
$ comm -13 tmp_A tmp_B
C
Simple - does exactly what I need - can't believe I didn't know about it...
Friday, May 31, 2013
Listing all the models and numbers of records in a Rails application
Here is a rake task that will list all the ActiveRecord models in a Rails application along with the number of database records in each and the last time that database table was updated. Note the call to eager_load which ensure that all models are loaded.
This is a simple but very useful way to assess the contents of your database.
This is a simple but very useful way to assess the contents of your database.
desc "List model in application"
task :list_models => :environment do
Rails.application.eager_load!
ActiveRecord::Base.descendants.each do |model|
name = model.name
count = model.count
last_date = count == 0 ? 'no data' : model.order('updated_at desc').first.updated_at
printf "%-20s %9d %s\n", name, count, last_date
end
end
Wednesday, April 17, 2013
Gotchas when working with HTML5 Audio
I've run into a few issues while building a demo web app that plays audio files, so I wanted to post my experiences...
1: Firefox does NOT play MP3 files (as of 2013-04-17)
This is because the MPEG format is proprietary and the Firefox/Mozilla folks insist on only open source formats. You need to use .wav, .ogg or .webm. See https://developer.mozilla.org/en-US/docs/HTML/Supported_media_formats for the allowed options.
Unfortunately they do not seem to produce a useful error message if you try and play an MP3 file.
Google Chrome plays anything - so your application may appear to work fine but may fail on Firefox.
2: Firefox is VERY strict in regard to Cross-Origin Resource Sharing (CORS)
Firefox will refuse to play an audio file on a host other than the one that served the original web page. So you can't store an audio file on, say, Amazon S3, and play it on your web site. The same goes for Ajax requests to another site. The Firefox console will, or may, display an error but this is not necessarily clear.
Google Chrome doesn't seem to care about this restriction.
See this page for more details https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
To work around this you can specify a header for the audio file which means that as the owner of the audio file you allow it to be referenced from any other site.
"Access-Control-Allow-Origin" = "*"
To work around the problem with Ajax requests you can use JSONP instead of JSON as I have described.
The special header ought to work with AWS S3... except....
3: AWS S3 does NOT allow the Access-Control-Allow-Origin header
You can set metadata headers with S3 files but not this one. The Amazon support forums are full of requests/complaints about this but it does not seem to have been resolved.
There does seem to be a way round this on Amazon Cloudfront, which pretty much exists to server assets for other sites, but from what I've seen this is pretty ugly.
My workaround for this was to add a proxy method to my server. The client requests a file that resides on S3 from the proxy. It fetches it from S3 and echoes it to the client, which sees it as coming from the originating server. This introduces an unnecessary delay but works file. Here is a snippet of code in Ruby for a Sinatra server. It uses the aws-sdk gem and leaves out set up for that.
get '/proxy' do
s3obj = bucket.objects[params['file']]
response["Access-Control-Allow-Origin"] = "*"
content_type 'audio/wav'
s3obj.read
end
Apparently Google's equivalent of S3 does not have this issue - I've not tried it.
4: You cannot play audio files from localhost
This makes testing a pain. Your audio files must be hosted on a server other than localhost. I recommend Heroku as a way to get development servers up and running quickly and at no initial cost.
If you don't realize this, then there is no error message in the browser console - it simply doesn't work and you are left scratching your head until you figure it out. I hate stuff like that...
1: Firefox does NOT play MP3 files (as of 2013-04-17)
This is because the MPEG format is proprietary and the Firefox/Mozilla folks insist on only open source formats. You need to use .wav, .ogg or .webm. See https://developer.mozilla.org/en-US/docs/HTML/Supported_media_formats for the allowed options.
Unfortunately they do not seem to produce a useful error message if you try and play an MP3 file.
Google Chrome plays anything - so your application may appear to work fine but may fail on Firefox.
2: Firefox is VERY strict in regard to Cross-Origin Resource Sharing (CORS)
Firefox will refuse to play an audio file on a host other than the one that served the original web page. So you can't store an audio file on, say, Amazon S3, and play it on your web site. The same goes for Ajax requests to another site. The Firefox console will, or may, display an error but this is not necessarily clear.
Google Chrome doesn't seem to care about this restriction.
See this page for more details https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
To work around this you can specify a header for the audio file which means that as the owner of the audio file you allow it to be referenced from any other site.
"Access-Control-Allow-Origin" = "*"
To work around the problem with Ajax requests you can use JSONP instead of JSON as I have described.
The special header ought to work with AWS S3... except....
3: AWS S3 does NOT allow the Access-Control-Allow-Origin header
You can set metadata headers with S3 files but not this one. The Amazon support forums are full of requests/complaints about this but it does not seem to have been resolved.
There does seem to be a way round this on Amazon Cloudfront, which pretty much exists to server assets for other sites, but from what I've seen this is pretty ugly.
My workaround for this was to add a proxy method to my server. The client requests a file that resides on S3 from the proxy. It fetches it from S3 and echoes it to the client, which sees it as coming from the originating server. This introduces an unnecessary delay but works file. Here is a snippet of code in Ruby for a Sinatra server. It uses the aws-sdk gem and leaves out set up for that.
get '/proxy' do
s3obj = bucket.objects[params['file']]
response["Access-Control-Allow-Origin"] = "*"
content_type 'audio/wav'
s3obj.read
end
Apparently Google's equivalent of S3 does not have this issue - I've not tried it.
4: You cannot play audio files from localhost
This makes testing a pain. Your audio files must be hosted on a server other than localhost. I recommend Heroku as a way to get development servers up and running quickly and at no initial cost.
If you don't realize this, then there is no error message in the browser console - it simply doesn't work and you are left scratching your head until you figure it out. I hate stuff like that...
Labels:
AWS S3,
CORS,
firefox,
google chrome,
html5,
javascript
Subscribe to:
Posts (Atom)