Perplexityに質問して、電話のプッシュ音を鳴らしてみた。JavascriptをAppInventorから呼び出す方法も。
今朝、ベッドから抜け出す前に、Perplexity(以下パープレ)をさわっていたんだけど、電話のプッシュ音を再現しようと調べ始めて途中でほってあったのを思い出し、Perplexity に質問してみたら、それっぽい回答が返ってきたので、最終App Inventorで鳴らすようにアプリを作成しました。
Perplexity にプログラムを書いてもらう
まずは、パープレに下記の質問を投げた
帰ってきたプログラムは音声ファイルを再生する仕組みで、音声ファイルは自分で探せという内容だったので、さらに
と投げた。そして帰ってきたのが、下のhtmlファイル
html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>公衆電話のプッシュ音 (WebAudio API)</title>
<style>
button {
font-size: 20px;
margin: 5px;
padding: 10px 20px;
}
</style>
</head>
<body>
<div id="keypad"></div>
<script>
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const dtmfFrequencies = {
'1': [697, 1209], '2': [697, 1336], '3': [697, 1477],
'4': [770, 1209], '5': [770, 1336], '6': [770, 1477],
'7': [852, 1209], '8': [852, 1336], '9': [852, 1477],
'*': [941, 1209], '0': [941, 1336], '#': [941, 1477]
};
function playTone(digit) {
const frequencies = dtmfFrequencies[digit];
const duration = 0.1; // 音の長さ(秒)
const oscillator1 = audioContext.createOscillator();
const oscillator2 = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator1.type = 'sine';
oscillator2.type = 'sine';
oscillator1.frequency.setValueAtTime(frequencies[0], audioContext.currentTime);
oscillator2.frequency.setValueAtTime(frequencies[1], audioContext.currentTime);
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
oscillator1.connect(gainNode);
oscillator2.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator1.start();
oscillator2.start();
oscillator1.stop(audioContext.currentTime + duration);
oscillator2.stop(audioContext.currentTime + duration);
}
const keypad = document.getElementById('keypad');
const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
keys.forEach(key => {
const button = document.createElement('button');
button.textContent = key;
button.onclick = () => playTone(key);
keypad.appendChild(button);
});
</script>
</body>
</html>
・WebAudio API を使用して、実際の音声ファイルを使用せずに音を生成
・各数字に対応する2つの周波数を使用して、DTMFトーンを生成
・音の減衰も対応してより近い音に調整
・キーパッドを動的に生成
と補足説明あり。
プッシュ音は図1のような周波数の正弦波を組み合わせて作成されているようだが、それらしき記述も読み取れる。
スマホのブラウザーで鳴らしてみる
コードを入手できたので、スマホのファイラーで空のテキストファイル(お約束のindex.html)を作成し、このコードを貼り付けて保存。
早速、ブラウザーに読み込んでみたら、ちゃんと音が出た。スマホの再生動画は下記(音がするだけですが)
App Inventor で、スマホのアプリを作成。スマホで鳴らす。
せっかくなんで、次にAppinventorのボタンで発音する仕組みも考えた。
手順は、
1.html ファイルをパソコンに移動し、操作ボタンなどApp Inventor で実現する不要な記述を削除。
2.修正後の htmlファイルを App Inventor のアセットにアップロード
3.Appinventorのデザイン編集画面で、ボタンとWebViewer を配置
4.ブロックを編集し、ボタンをクリックすると、JavaScript を起動しボタンに対応した音を鳴らすようにする
html ファイルをパソコンに移動し、App Inventor では不要なHTML表示部分を削除する
App Inventor で利用するために、スマホで作成した index.html をパソコンに移動し、アセットにアップロードするが、ボタンは Appinventorのボタン使うため、HTMLのボタン表示の部分は必要ないので、下記2点を削除した。
・<script>~</script>の前後のHTMLの表示部分を削除
・<script>~</script>内部後半のキーパッド表示部分の記述を削除
<script>
// AudioContextを作成(ブラウザ互換性のために両方の名前を使用)
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
// DTMF(Dual-tone multi-frequency)周波数のマッピング
const dtmfFrequencies = {
'1': [697, 1209], '2': [697, 1336], '3': [697, 1477],
'4': [770, 1209], '5': [770, 1336], '6': [770, 1477],
'7': [852, 1209], '8': [852, 1336], '9': [852, 1477],
'*': [941, 1209], '0': [941, 1336], '#': [941, 1477]
};
// 指定された数字のトーンを再生する関数
function playTone(digit) {
// 数字に対応する周波数を取得
const frequencies = dtmfFrequencies[digit];
const duration = 0.1; // 音の長さ(秒)
// オシレーターを2つ作成
const oscillator1 = audioContext.createOscillator();
const oscillator2 = audioContext.createOscillator();
const gainNode = audioContext.createGain();
// オシレーターのタイプをサイン波に設定
oscillator1.type = 'sine';
oscillator2.type = 'sine';
// オシレーターの周波数を設定
oscillator1.frequency.setValueAtTime(frequencies[0], audioContext.currentTime);
oscillator2.frequency.setValueAtTime(frequencies[1], audioContext.currentTime);
// ゲインノードの初期ゲインを設定し、音がフェードアウトするようにする
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
// オシレーターをゲインノードに接続
oscillator1.connect(gainNode);
oscillator2.connect(gainNode);
// ゲインノードをオーディオコンテキストの出力に接続
gainNode.connect(audioContext.destination);
// オシレーターを開始し、指定した時間後に停止
oscillator1.start();
oscillator2.start();
oscillator1.stop(audioContext.currentTime + duration);
oscillator2.stop(audioContext.currentTime + duration);
}
</script>
htmlファイルをApp Inventor のアセットに登録
不要な処理を削除したhtmlファイルをアセットにアップロードします。
1.デザインビューで、ボタンを並べる。ボタンの表示をJavascript への引数とするため、ボタンの文字は半角で記述する
2.htmlファイルをアセットにアップロードし、WebviewerのHomeUrl プロパティにファイル名を設定しますが、頭に Localhosut/ を付けて、Localhost/index.html として、ファイルの場所がアセットだと指定します。
ブロック編集。Javascriptの関数をApp Inventor から呼び出す
ブロック編集画面は、図3です。ブロックのクリックメニューの Make Generic を用いて、どのボタンを押してもそのボタンのテキストを引数とした Javascript の関数を起動します。
完成したスマホ画面
完成したスマホの画面が図〇です。ボタンをクリックするとプッシュ音(もどき)が鳴るだけのアプリです。
サンプルを自分の環境に読み込んで試してください
実際に試していただけばと思います。
サンプルのaiaファイルは下記です。Javascriptファイルもセットされてます。
(以上)