script.aculo.usを読み解く

第8回 sound.js

この記事を読むのに必要な時間:およそ 3 分

連載8回目は,ブラウザで音を鳴らすためのライブラリ,sound.jsを解説します。ページにちょっとした効果音をつけることで,ユーザの注意を引きつけることができます。音声制御の機能としては,再生と停止だけの,単純なものしか用意されていないので,例えば,以下のような用途が向いています。

  • 時間のかかるアップロードの終了時に音を鳴らす(このときブラウザのウィンドウが隠れていても大丈夫です)
  • チャットのお知らせ音
  • 認証失敗のビープ音
  • 後戻りできない処理の警告音
  • 短い音声による案内

内部的には,ページにembedタグを挿入して,ブラウザのQuickTimeプラグインを使うことで実現されています。IEでは,ページにbgsoundタグを挿入して,IEに固有の音声再生機能を使います。

なぜFlashを使わないのかについては,いまだ議論の余地がありますが,最近はQuickTimeプラグインがiTunesの成功からよくインストールされていること,MacにはQuickTimeが最初から入っていることが,まずは大きな理由です。そしてまた,このscript.aculo.usが,Flashに頼らずにここまでできるというコンセプトで開発されているから,ということもあるでしょう。

並行に音を鳴らすこともできます。これには,embedタグ(IEではbgsoundタグ)をページに複数置くようになっています。また,"トラック"の機能があります。これは,複数の音をひとまとめに扱うための仕組みです。

次のように使います。

// 音声を再生する。トラックは'global'
Sound.play('blah.mp3');
// 'global'にある全ての音を止めてから,改めて音声を再生する。
Sound.play('blah.mp3',{replace:true});
// 'mytrack'で再生する。(この関数を同様に何度も呼び出すことで,複数の音を登録できます)
Sound.play('blah.mp3',{track:'mytrack'});
// 'mytrack'にある全ての音を止めてから,改めて音声を再生する。
Sound.play('blah.mp3',{track:'mytrack',replace:true});

それではコードを見ていきましょう。

0001:// script.aculo.us sound.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
0002:
0003:// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
0004://
0005:// Based on code created by Jules Gravinese (http://www.webveteran.com/)
0006://
0007:// script.aculo.us is freely distributable under the terms of an MIT-style license.
0008:// For details, see the script.aculo.us web site: http://script.aculo.us/
0009:

1~9行目は,著作権表示です。

Sound

0010:Sound = {
0011:  tracks: {},
0012:  _enabled: true,

11行目の,tracksは,トラックの情報が入るオブジェクトで,キーにトラック名,値にそのトラックの情報が入ります。今のところその情報は,トラックに含まれる音の数だけです。0から数えるので,例えば'global'トラックに音が2つあるときは,global: {id: 1}となります。

12行目の,_enabledは,再生を行うかどうかのフラグです。初期値はtrueです。後述のenable,disableメソッドで切り替えます。

0013:  template:
0014:    new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),

13,14行目の,templateは,prototype.jsのTemplate機能を使って,embedタグの文字列テンプレートを作っています。QuickTimeプラグインには,height属性が必須です。idには,このトラックの何番めの音,と後で入ります。srcには,再生する音のアドレスが,後で入ります。loopが"false"なので,再生は1回です。autostartが"true"なので,自動で再生が始まります。hiddenが"true"なので,画面に表示されません。

0015:  enable: function(){
0016:    Sound._enabled = true;
0017:  },
0018:  disable: function(){
0019:    Sound._enabled = false;
0020:  },

15~17行目の,enableは,再生機能を有効にする関数です。

18~20行目の,disableは,再生機能を無効にする関数です。

0021:  play: function(url){
0022:    if(!Sound._enabled) return;
0023:    var options = Object.extend({
0024:      track: 'global', url: url, replace: false
0025:    }, arguments[1] || {});
0026:    
0027:    if(options.replace && this.tracks[options.track]) {
0028:      $R(0, this.tracks[options.track].id).each(function(id){
0029:        var sound = $('sound_'+options.track+'_'+id);
0030:        sound.Stop && sound.Stop();
0031:        sound.remove();
0032:      })
0033:      this.tracks[options.track] = null;
0034:    }
0035:      
0036:    if(!this.tracks[options.track])
0037:      this.tracks[options.track] = { id: 0 }
0038:    else
0039:      this.tracks[options.track].id++;
0040:      
0041:    options.id = this.tracks[options.track].id;
0042:    $$('body')[0].insert( 
0043:      Prototype.Browser.IE ? new Element('bgsound',{
0044:        id: 'sound_'+options.track+'_'+options.id,
0045:        src: options.url, loop: 1, autostart: true
0046:      }) : Sound.template.evaluate(options));
0047:  }
0048:};
0049:

21~48行目の,playは,再生したい音声を追加する関数です。1番めの引数に音声ファイルのアドレスを与えます。2番めの引数にオプションを与えることができます。オプションには,trackでトラック名を設定し,replaceで既にトラックにある音を止めるかを設定します。

22行目で,もし機能が無効なら何もしません。

23行目で,デフォルトのオプションは,トラック名は'global',replaceは'false'です。よって,'global'トラックに追加されて並行に再生されます。

27行目で,replaceオプションが真で,かつ,trackオプションで指定されたトラックが既にある場合,トラックの全ての音を止めるために,以下の処理をします。

28行目で,そのトラックのそれぞれの音のidを,eachメソッドでたどります。これはtimesメソッドを使ってもよいでしょう。

29行目で,idに対応する要素を取得します。

30行目で,QuickTimeのStopメソッドを使って再生を停止します。

31行目で,prototype.jsのremoveメソッドで要素をDOMから削除します。

33行目で,そのトラックの情報をnullにします。これは,トラックにひとつも音が含まれていないことを意味します。

ここから,トラックに音を追加する処理に入ります。

36~39行目で,トラックにひとつも音が含まれていなければ,{id:0}とします。既に含まれていれば,idのカウントを増やします。

42~46行目で,body要素の下に,音声を再生するタグを挿入します。IEであればbgsoundタグを,そうでなければ,templateのタグを挿入します。

0050:if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
0051:  if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
0052:    Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>')
0053:  else
0054:    Sound.play = function(){}
0055:}

50行目で,ブラウザがFirefoxで,特にWindows上で実行されているかを調べます。

51行目で,その場合,pluginsの情報からQuickTimeがインストールされているかどうかをチェックします。

52行目で,もしインストールされていれば,templateをobjectタグを使うものに置き換えます。

54行目で,もしされていなければ,play関数をつぶして,一切を無効にします。

著者プロフィール

源馬照明(げんまてるあき)

名古屋大学大学院多元数理科学研究科1年。学部生のときにSchemeの素晴らしさを知ったのをきっかけに,関数型言語の世界へ。JavaScriptに,ブラウザからすぐに試せる関数型言語としての魅力と将来性を感じている。

ブログ:Gemmaの日記

コメント

コメントの記入