ステレオ音声再生実験
はじめに
IEに備わっている音楽演奏・音声再生機能(BGSOUNDオブジェクト)の動作試験です。ページを開くとシラネーヨ(ならびにモナー)のステレオ音声が再生されます。ヘッドホンで聴くと,あたかもシラネーヨが目の前を通りすぎたり,突然近づいてきたりする‥‥ハズなのですが,まだ試行錯誤の段階なもので,そのような錯覚を覚えるほど完成度は高くありません。時折,音声に「プチプチ」っていう雑音が入って耳障りなのですが,今後改善できるかどうか分りません。
この動的コンテンツはInternet Explorerでなければ実行できません。
注意事項
- 音声が出ないときは,音の鳴るアプリケーション(“Windows Media Player”など)が動作していないか確認してください。もし動作しているならそのアプリケーションを終了させて,このウェブページを開き直して(リロードして)ください。
- ボタン操作のタイミングによって,以後マウス操作ができなくなることがあります。そんなときはバックスペースキーを押してください。
- Windows2000のIE5.5で動作確認しております。
- 長時間視聴すると“は○じん”になるかもしれません。お気をつけください。
コンソールの使い方
- 音声選択: 再生する音声ファイルを選択します。
- 操作:「連続再生」ボタンを押すと,音声を繰り返し再生します。「停止」ボタンを押すと停止します。
- バランス: 音声のバランス(左右のスピーカのどちらに音声を寄せるか)を調整します。「左」,「中央」,「右」を押すと任意にバランスが切り替わります。「≪」,「≫」はバランスを微調整するボタンです。「自動」を選択しているときは,あらかじめ決められた周期でバランスが遷移します。
- 音量:音量をセットします。「最小」は無音。「最大」は通常の音量です(スピーカが張り裂けんばかりの大音量にはなりません)。「自動」を選択しているときは,あらかじめ決められた周期で音量が遷移します。
- メタ情報:BGSOUNDオブジェクトの情報が表示されます。
音声ファイルの説明
- [MP3] シラネーヨ
「シラネーヨ」の声です。この音声は,私の声を元に音声処理装置で加工したものです。 - [MP3] マターリしよーヨ
上と同じ「シラネーヨ」の声です。「第2回音声伝送実験」で公開した音声ファイルと同一です。 - [MP3] オマエモナー
「モナー」の声です。ふしぎ少女風(なぞ)にしてみました。
※音声ファイルの容量はどれも30kバイト程度と小さいのですが,ネットワークの状態によってロードに時間が掛かったり,失敗したりすることがあるかもしれません。
技術資料
使用ツール:Microsoft Visual J++ 6.0
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 98">
<META HTTP-EQUIV="Content-Type" content="text/html">
<bgsound id=sound>
<script><!--
function SoundDecorator(target) {
this.target = target;
this.src;
}
SoundDecorator.prototype.PAN_LEFT = -10000;
SoundDecorator.prototype.PAN_CENTER = 0;
SoundDecorator.prototype.PAN_RIGHT = +10000;
SoundDecorator.prototype.VOLUME_MAX = 0;
SoundDecorator.prototype.VOLUME_MIN = -10000;
SoundDecorator.prototype.setPan = function (val) {
switch (val) {
case 'center':
this.target.balance = this.PAN_CENTER;
break;
case 'right':
this.target.balance = this.PAN_RIGHT;
break;
case 'left':
this.target.balance = this.PAN_LEFT;
break;
default:
if (typeof val == 'number') {
this.target.balance = val;
}
break;
}
}
SoundDecorator.prototype.getPan = function () {
return this.target.balance;
}
SoundDecorator.prototype.setVolume = function (val) {
this.target.volume = val;
}
SoundDecorator.prototype.getVolume = function () {
return this.target.volume;
}
SoundDecorator.prototype.setSrc = function (src) {
this.src = src;
}
SoundDecorator.prototype.getSrc = function () {
return this.src;
}
SoundDecorator.prototype.play = function () {
if (arguments.length == 1) {
this.setSrc(arguments[0]);
}
this.target.loop = 1;
this.target.src = this.src;
}
SoundDecorator.prototype.repeat = function () {
if (arguments.length == 1) {
this.setSrc(arguments[0]);
}
this.target.loop = -1;
this.target.src = this.src;
}
SoundDecorator.prototype.stop = function () {
this.target.src = null;
}
SoundDecorator.prototype.toString = function () {
return "properties={"
+ "src=\"" + this.target.src + '"'
+ ","
+ "loop=" + this.target.loop
+ ","
+ "volume=" + this.target.volume
+ ","
+ "balance=" + this.target.balance
+ "}";
}
////////
var sd = new SoundDecorator(sound);
var demo1ID = null, demo2ID = null;
function setDemo1(op) {
if (demo1ID != null) {
clearInterval(demo1ID);
demo1ID = null;
sd.setPan(sd.PAN_CENTER);
panPanel.disabled = false;
}
if (op) {
var demo = new function (sdecorator) {
this.sound = sdecorator;
this.array = new Array();
this.index = 0;
var i = 0;
var step = 500;
for (var pan = -5000; pan <= 5000; pan += step) {
this.array[i ++] = pan;
}
for (var pan = 5000; pan >= -5000; pan -= step) {
this.array[i ++] = pan;
}
this.exec = function () {
this.sound.setPan(this.array[this.index]);
this.index = (this.index + 1) % this.array.length;
}
} (sd); // 無名オブジェクトのコンストラクタの引数
var functor = function () {
demo.exec();
}
demo1ID = setInterval(functor, 400);
panPanel.disabled = true;
}
}
function setDemo2(op) {
if (demo2ID != null) {
clearInterval(demo2ID);
demo2ID = null;
volumePanel.disabled = false;
}
if (op) {
var demo = new function (sdecorator) {
this.sound = sdecorator;
this.array = new Array();
this.index = 0;
var i = 0;
var step = 500;
for (var pan = -5000; pan <= 0; pan += step) {
this.array[i ++] = pan;
}
for (var pan = 0; pan >= -5000; pan -= step) {
this.array[i ++] = pan;
}
this.exec = function () {
this.sound.setVolume(this.array[this.index]);
this.index = (this.index + 1) % this.array.length;
}
} (sd);
var functor = function () {
demo.exec();
}
demo2ID = setInterval(functor, 400);
volumePanel.disabled = true;
}
}
function selectSource(filename) {
sd.setSrc(filename);
sd.repeat();
}
////////
function update() {
function updatePanIndicator() {
var currentPan = sd.getPan();
var leftValue, rightValue;
if (currentPan == sd.PAN_CENTER) {
leftValue = 0;
rightValue = 0;
} else {
if (currentPan < sd.PAN_CENTER) {
leftValue = 0;
rightValue = -currentPan / 100;
} else {
leftValue = currentPan / 100;
rightValue = 0;
}
}
console.panIndicator.value = ""
+"L = -" +leftValue + "db"
+","
+"R = -" +rightValue + "db";
var isLeft = (currentPan <= sd.PAN_LEFT);
var isRight = (currentPan >= sd.PAN_RIGHT);
var isCenter = (currentPan == sd.PAN_CENTER);
console.leftPanButton.disabled = isLeft;
console.leftShiftPanButton.disabled = isLeft;
console.centerPanButton.disabled = isCenter;
console.rightShiftPanButton.disabled = isRight;
console.rightPanButton.disabled = isRight;
}
function updateVolumeIndicator() {
var currentVolume = sd.getVolume();
console.volumeIndicator.value = currentVolume / 100 + "db";
var isMaximum = (currentVolume >= sd.VOLUME_MAX);
var isMinimum = (currentVolume <= sd.VOLUME_MIN);
console.decVolumeButton.disabled = isMinimum;
console.incVolumeButton.disabled = isMaximum;
console.minimizeVolumeButton.disabled = isMinimum;
console.maximizeVolumeButton.disabled = isMaximum;
}
updatePanIndicator();
updateVolumeIndicator();
console.detailField.value = sd;
}
function init() {
console.demo1switch.checked = true;
console.demo2switch.checked = true;
setDemo1(console.demo1switch.checked);
setDemo2(console.demo2switch.checked);
selectSource(console.fileSelector.value);
////
setInterval(function () {update();}, 250);
}
window.onload = init;
//--></script>
</HEAD>
<BODY>
<form id=console style="border:solid;border-color:#c60;background-color:#fc9;padding-left:20px">
<div style="color:white;margin-left:-20px;background-color:#f90;font-weight:bold">コンソール</div>
<div style="margin-top:10px">
音声選択
<select id=fileSelector onchange="selectSource(this.value)">
<option value="au-shiraneyo-9788364805.mp3" selected>( ´ー`) シラネーヨ
<option value="au-mattari-9779724812.mp3">( ´ー`) マターリしよーヨ
<option value="au-omaemona-9788364795.mp3">( ´∀`) オマエモナー
</select>
</div>
<div style="margin-top:10px">
操作
<input type=button value="連続再生" id=playButton onclick="sd.repeat()">
<input type=button value="停止" id=stopButton onclick="sd.stop()">
</div>
<div style="margin-top:10px">
バランス<br>
<input type=checkbox id=demo1switch onclick="setDemo1(this.checked)">自動<br>
<div id=panPanel style="margin-left:5px">
<input type=button value="左" id=leftPanButton onclick="sd.setPan(sd.PAN_LEFT)">
<input type=button value="中央" id=centerPanButton onclick="sd.setPan(sd.PAN_CENTER)">
<input type=button value="右" id=rightPanButton onclick="sd.setPan(sd.PAN_RIGHT)">
<input type=button value="≪" id=leftShiftPanButton onclick="sd.setPan(sd.getPan() - 250)">
<input type=button value="≫" id=rightShiftPanButton onclick="sd.setPan(sd.getPan() + 250)">
<input type=text id=panIndicator disabled size=25>
</div>
</div>
<div style="margin-top:10px">
音量<br>
<input type=checkbox id=demo2switch onclick="setDemo2(this.checked)">自動<br>
<div id=volumePanel style="margin-left:5px">
<input type=button value="最小" id=minimizeVolumeButton onclick="sd.setVolume(sd.VOLUME_MIN)">
<input type=button value="最大" id=maximizeVolumeButton onclick="sd.setVolume(sd.VOLUME_MAX)">
<input type=button value=" - " id=decVolumeButton onclick="sd.setVolume(sd.getVolume() - 250)">
<input type=button value=" + " id=incVolumeButton onclick="sd.setVolume(sd.getVolume() + 250)">
<input type=text id=volumeIndicator disabled>
</div>
</div>
<div style="margin-top:10px">
メタ情報<br>
<textarea cols=60 rows=4 id=detailField wrap=virtual disabled></textarea>
</div>
</form>
</BODY>
</HTML>