2018年11月1日木曜日

サウンドを出そう!

スマホでサウンドを出す方法について説明します。
まず、MonacaでYes/Noチャートのプロジェクトを開きます。左側のプロジェクトブラウザでwwwフォルダの下にjsフォルダを作成します。これはjavascriptを格納するためのフォルダとして使います。次にjsフォルダの中にmain.jsというファイルを新規作成します。その中に次のコードを書きます。
var beep = function() {
    var my_media = new Media("https://maoudamashii.jokersounds.com/music/se/wav/se_maoudamashii_chime03.wav",
        // success callback
        function() {
            console.log("playAudio():Audio Success");
        },
        // error callback
        function(err) {
            console.log("playAudio():Audio Error: "+err);
    }).play();
};
リスト 1
これは、音を鳴らす関数beepの定義です。
次に、index.htmlでmain.jsを取り込むように以下の1行を<head>~</head>の中に追加します。ほかにもscriptタグがいくつかあるのでその下に追加すればよいでしょう。
<script src="js/main.js"></script>
リスト 2
こうして定義したbeep音を出すにはbeep()関数を呼び出します。例えば下のコードのように、ボタンをクリックしたとき(onclick)にbeep()関数を実行します。
<ons-button class="no-btn" onclick="beep()">
    音楽
</ons-button>
リスト 3
なお、beep音の指定はリスト1の3行目で行っています。Mediaオブジェクトを生成するとき、出したい音のURLを引数に指定します。サウンドファイルであればどのような形式でもOKみたいです。
フリーの音源は下記サイトにあるのでいろいろと試してください。
https://maoudamashii.jokersounds.com/


ページが開くと同時に音を出す


ここまでだと、[音楽]とラベルの付いたボタンをクリックしないと音が出ません。ページが開くと同時に音が出るようにしてみましょう。
そのためには、ページが開いたというタイミングを捉まえる必要があります。これについては、下記のサイトに書いてあるons-nabigatorのイベントpostpushを利用します。
https://ja.onsen.io/v2/api/js/ons-navigator.html
詳細については、このサイトの「postpush」の記載を見てください。

以下に修正手順を示します。
まず、効果音を出したいページのHTMLファイルを次のように修正します。
ons-pageタグにid属性を付けます。その際、idの値はファイル名から.htmlを除いた部分とします。
例として、HTMLファイル名がresult_Cat.htmlの場合を以下に示します。
<ons-page id="result_Cat">
    <ons-toolbar>
        <div class="center">診断結果</div>
    </ons-toolbar>
    <div class="pagebody">
        <h1>猫タイプ</h1>
        <img src="images/cat.png">
        <p>猫タイプのあなたは、何ものにも縛られない自由人。気まぐれで自由奔放な性格に、周囲の人は振り回されているかも?</p>
        <ons-button class="retry-btn" onclick="document.getElementById('navi').resetToPage('question_A.html')">
            もう一度
        </ons-button>
    </div>
</ons-page>
リスト4
修正したのは1行目です。ons-pageタグの属性にid="result_Cat"を付け加えました。
次に、main.jsに次のコードを付け加えます。
document.addEventListener('postpush', function(event) {
  if(event.enterPage.id == 'result_Cat') {
    beep('https://maoudamashii.jokersounds.com/music/se/wav/se_maoudamashii_chime03.wav');
  }
}, false);
リスト5
これは、ページがプッシュ(表示)された後に発生するons-navigatorpostpushイベントを捉まえて、効果音を鳴らすための処理です。
どのページが表示されたかを判定するために、イベント関数に渡された引数evententerPageオブジェクトを調べます。
enterPageオブジェクトには、表示されたページの属性が入っています。どのページかを判断するにはid属性を見ます。
上記のリスト5では、id属性'result_Cat'の場合(つまりリスト4のページの場合)にbeep関数を使って効果音を鳴らしています。

【Tips】


Onsen UIはVer.1とVer.2では仕様がだいぶ変わっている。詳細は下記 Onsen UI 1.xからの移行を参照してください。
https://ja.onsen.io/v1/from-v1-to-v2.html
例えば、ons-navigatorタグにvar属性で名前を付けて、それを変数名としてjavascriptでons-navigator要素を操作するといったことはできなくなっています。id属性を付けて普通のDOM要素と同様にしてdocument.getElementByIdを使ってons-navigatorにアクセスします。また、イベントの捉え方なども違っているのでOnsen UI Ver.2のドキュメントを参照しながらプログラムする必要があります。


動画を再生する


次に動画を再生する方法について説明します。
まず、wwwフォルダの下に動画を保存するフォルダvideoを作成します。そして再生したい動画ファイルをその中にアップロードします。動画はスマホで撮影したものを使います。
動画の準備ができたら、まず、HTMLファイルを編集します。動画を再生するページ(例えばresult_Cat.html)の</div>タグの上に以下の<video>タグを追加します。
<video id="video1" src="video/XXXXXX" width="320" height="240" controls></video>
リスト6
ここで、XXXXXXの部分は自分が撮影してvideoフォルダにアップロードした動画ファイルの名前に置き換えてください。
次にjsフォルダにあるmain.jsを開いてリスト5のbeep関数呼び出しの下に動画を再生するプログラムを書きます。リスト5のプログラムを次のように書き換えてください。
document.addEventListener('postpush', function(event) {
  if(event.enterPage.id == 'result_Cat') {
    beep('https://maoudamashii.jokersounds.com/music/se/wav/se_maoudamashii_chime03.wav');
    var video = document.getElementById("video1");
    video.play();
  }
}, false);
リスト7
付け加えたのは4~5行目の2行だけです。これで完成しました。あとはスマホでアプリを動かして動画が再生できることを確認してください。


カメラで撮影する(静止画編)

cordova-plugin-camera v4.0.1 を使ってカメラアプリを起動する方法について解説します。ここでは、カメラアプリで静止画を撮影し、撮影した画像ファイルをスマホに保存するアプリを作成することにします。

まず、カメラを起動するためのボタンと撮影した画像を表示するページを作成します。ここでは、Yes/Noチャートのquestion_C.htmlを改造することにします。
question_C.htmlをリスト8に示します。
<ons-page id="pageC">
    <ons-toolbar>
        <div class="left"><ons-back-button>Back</ons-back-button></div>
        <div class="center">設問C</div>
    </ons-toolbar>

    <div class="pagebody">
        <h1 class="question">約束当日にドタキャンしたことが何回かある。</h1>
        <ons-button class="yes-btn"
            onclick="">
            はい
        </ons-button>
        <ons-button class="no-btn"
            onclick="">
            NO
        </ons-button>
        <ons-button class="no-btn" id="camera-btn-C"
            onclick="">
            カメラ
        </ons-button>
        <div id="viewport-C" class="viewport" style="display: none;">
            <img style="width:200px;" id="image-C" src="" />
        </div>
   </div>
</ons-page>
リスト8

追加したのは17~23行目です。17~20行目は「カメラ」というラベルの付いたボタンの定義で、21~23行目は撮影した画像を表示するためのimgタグです。下図はこうして作成したページCの画面です。

図1 ページCの画面

次にmain.jsの末尾にリスト9のコードを追加します。ここでは、ページが初期化されたときに発火するinitイベントを捉えて、そこに図1の[カメラ]ボタンがクリックされたときの処理を書きます。
document.addEventListener('init', function(event) {
  var page = event.target;
  if(page.id == 'pageC') {
    document.getElementById("camera-btn-C").addEventListener('click', function() {
      navigator.camera.getPicture(function(url){
        var viewport = document.getElementById('viewport-C');
        viewport.style.display = "";
        document.getElementById("image-C").src = url;
      }, function(){
        alert('撮影できませんでした!');
      }, {
        quality : 50,
        destinationType: Camera.DestinationType.FILE_URI,
        targetWidth: 500,
        targetHeight: 500
      });
    });
  }
});
リスト9 ページが初期化されたときの処理

1行目はinitイベントのイベントリスナの定義です。initイベントはページが初期化されるときに発火します。どのページが発火したかはeventオブジェクトのid属性で判定します。3行目のif文で"pageC"の場合に[カメラ]ボタンがクリックされたときのイベントリスナを定義します。

ここでは、[カメラ]ボタンが押されたら5行目でCordovaのカメラプラグイン(cordova.camera)を使ってカメラアプリを起動します。5行目のnavigator.camera.getPicture関数がそれです。この関数は第1引数に撮影が成功したときに実行するコールバック関数を、第2引数には失敗したときのコールバック関数を、そして第3引数にはオプションを書きます。
オプションには取得する画像の画質を指定するquality (0~100)やgetPicture()が返す形式を指定するdestinationType (Camera.DestinationType.DATA_URL: Base64でエンコードしたテキストデータを返す、Camera.DestinationType.FILE_URI:画像ファイルへのパスを返す)などを指定します。

撮影に成功したときは 6~8行目のコードが実行されます。画像表示領域を可視状態にし、imgタグのsrcプロパティに撮影した画像のURIを代入します。

図2.撮影した画像を画面表示


動画撮影 


次に動画を撮影して撮影するプログラムを書きます。動画を撮影するにはCordovaのメディアキャプチャプラグイン(cordova-plugin-media-capture)のnavigator.device.capture.captureVideo関数を使います。

ここでは、Yes/NoチャートのページEを使って動画撮影と再生を行います。リスト10はページEのHTMLです。
<ons-page id="pageE">
    <ons-toolbar>
        <div class="left"><ons-back-button>Back</ons-back-button></div>
        <div class="center">設問E</div>
    </ons-toolbar>

    <div class="pagebody">
        <h1 class="question">一人より大勢でいるほうが好きだ。</h1>
        <ons-button class="yes-btn"
            onclick="">
            YES
        </ons-button>
        <ons-button class="no-btn"
            onclick="">
            NO
        </ons-button>
        <ons-button class="no-btn" id="movie-btn-E"
            onclick="">
            動画撮影
        </ons-button>
        <video id="video-E" src="" width="320" height="240" controls></video>
    </div>
</ons-page>
リスト10

1行目のons-pageタグのid属性にpageEを設定します。
17行目~20行目は[動画撮影]ボタンの定義で、これをクリックするとカメラアプリが起動され、動画の撮影が行えます。
21行目は撮影した動画を再生させるためのvideoタグです。実際の画面は次のようになります。

図3 ページEの画面


次にmain.jsのinitイベントリスナにページEが初期化されたときの処理を書きます。
それをリスト11に示します。
  } else if(page.id == 'pageE') {
    document.getElementById("movie-btn-E").addEventListener('click', function() {
      navigator.device.capture.captureVideo(function(mediaFiles){
        mediaFiles.forEach(function( mediaFile ) {
          var video = document.getElementById("video-E");
          video.src = mediaFile.fullPath;
          video.play();
        });
      }, function(error){
        navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
      }, {
        limit: 2
      });
    });
  }
リスト11

なお、リスト11では関係のない部分は削除しています。
2行目は[動画撮影]ボタンがクリックされたときに実行するイベント処理を登録しているところです。処理の中身はビデオ撮影です。これは navigator.device.capture.captureVideo()関数で行います。
この関数の第1引数には撮影成功時のコールバック関数が書かれています。その内容は、リスト10の21行目のvideoタグに撮影した動画を流す処理です。
実際の画面は次のようになります。

図4.動画再生


【TIPS】


Onsen UI (Monaca Version)を使った場合、ons-navigatorのpage属性にしたHTMLはons-templateタグを使ってindex.htmlと同じファイル内に書かないとDOMがRead Onlyになってしまうという奇妙な現象が現れた。
にもかかわらず、別ファイルにしてしまうと認識されない。よって、別ファイルにしつつ、index.html内にons-templateタグで存在のみ指定するという奇妙な書き方をしないとこの問題を回避できない。
この現象は、ons-navigatorのpage属性にしたHTML以外では生じないので、バグではないかと思うが、気持ちが悪いので、[設定]→[JS/CSSコンポーネントの追加と削除]でOnsen UI (Monaca Version)を削除した。

0 件のコメント:

コメントを投稿