質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.50%

WebAudioApiでのクラス化が上手く出来ません

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,000

morikz

score 69

//Lineクラス
var Line = function(length){
    this.audioContext
    this.wetGainNode;
    this.lineNum;
    
    Line.prototype.init(length);
}

Line.prototype.init = function(length){
    //クラスのブラウザ別振り分け
    var webAudioAPI = (window.AudioContext ||
        window.webkitAudioContext ||
        window.mozAudioContext ||
        window.oAudioContext ||
        window.msAudioContext);
        
    /* 外部クラスインスタンス化 */
    this.audioContext = new webAudioAPI();

    /* 各種ノード生成 */
    this.wetGainNode = this.audioContext.createGain();    //wetGainNode
    
    /* wetGain初期化 */
    this.wetGainNode.gain.value = 0;
    
    /* LineContainer ModuleRoot要素の作成 */
    Line.prototype.createElem(Line.prototype.setLineNum(length));
}

Line.prototype.getWetGain = function(){
    return this.wetGainNode.gain.value;
}

Line.prototype.setWetGain = function(val){
    this.wetGainNode.gain.value = val;
}

Line.prototype.paramView = function(obj){
    console.log('wetGain : ' + obj.getWetGain());
}

Line.prototype.setLineNum = function(length){
    return this.lineNum = length;
}

Line.prototype.createElem = function(linenum){
    //HTML構造生成
    var pElem = document.querySelector('#lineContext');        //lineContext取得
    var lineContainer = document.createElement("div");                //lineContainer
        lineContainer.className = "lineContainer";
        lineContainer.setAttribute('data-linenum', linenum);
    /*-------------------------------wetGain-------------------------------*/
    //wetGainContainer
    var wetGainContainer = document.createElement("div");
    wetGainContainer.className = "wetGain";
    
    //h3
    var wetGain__p = document.createElement("p");
    wetGain__p.innerHTML = "wetGain";
    
    //wetGainView
    var wetGainView = document.createElement("div");
    wetGainView.className = "wetGainView";
    wetGainView.innerHTML = "0";
    
    //wetGain
    var wetGainInput = document.createElement("input");
    wetGainInput.className = "wetGainInput";
    wetGainInput.type = "range";
    wetGainInput.value = "0";
    wetGainInput.step = "1";
    wetGainInput.max = "100";
    /*----------------------------------------------------------------------*/
    
    
    
    /*----------------------------------------------------------------------*/
    
    /*-------------------------------appendChild----------------------------*/
    //wetGain - appendChild
    wetGainContainer.appendChild( wetGain__p );
    wetGainContainer.appendChild( wetGainView );
    wetGainContainer.appendChild( wetGainInput );
        
    //p - appendChild
    pElem.appendChild( lineContainer );
    lineContainer.appendChild( wetGainContainer );
    /*----------------------------------------------------------------------*/
}
//イベントリスナー登録
document.addEventListener('DOMContentLoaded', function (event) {
    
    var lines = new Array();
    
    //Line作成
    event.target.querySelector('#createButton').addEventListener('click', function(){
        
        //インスタンスpush
        lines.push(new Line(lines.length));
    
        var wetGainInputElem = document.querySelectorAll('.wetGainInput');
        var wetGainView = document.querySelectorAll('.wetGainView');
        
        for(var i = 0; i < lines.length; i++){
            
            //スライドバーリスナー登録
            wetGainInputElem[i].addEventListener("input", function(event){
                var input = event.target;
                var view = input.previousElementSibling;
                var lineElem = input.parentNode.parentNode;                //class="lineContainer"
                var lineNum = lineElem.getAttribute('data-linenum');
                
                var volume = this.value;        //gain値の変更
                view.innerHTML = volume;        //表示の変更
                lines[lineNum].setWetGain(volume);    //イベントがあったインスタンスのメンバ変数にアクセスしてセット
            }, false);
        }
    }, false);
    
    //Lineの状態参照
    event.target.querySelector('#checkSource').addEventListener('click', function(){
        if(lines.length > 0){
            for(var i=0; i < lines.length; i++){
                lines[i].paramView(lines[i]);
            }
        }
    }, false);
    
}, false);
<!doctype html>
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./css/common.css">
<title>Web Audio Player</title>
<style type="text/css">
</style>
</head>
<body>
    
    <i id="createButton" class="fa fa-plus-square"></i>
    
    <i id="checkSource" class="fa fa-search-plus"></i>
    
    <div id="lineContext">
    </div>
    
<script type="text/javascript" src="js/LineClass_clone.js" charset="utf-8"></script>
<script type="text/javascript" src="js/controller_clone.js" charset="utf-8"></script>
</body>
</html>
@charset "utf-8";
* {
    margin: 0;
    padding: 0;
}
body {
    background-color: #420202;
}
.lineContainer {
    background-color: #f2f2f2;
    padding: 10px 10px;
    margin: 5px;
    width: 220px;
    border-radius:5px;
    border: solid 2px gray;
    float: left;
}
.wetGainView,.dryGainView,.delayGainView,.feedbackView {
    float:left;
    width: 15px;
    margin-left: 15px;
    font-size: 10px;
}
.wetGain,.dryGain,.delayGain,.feedback{
    margin-left: 15px;
}
.wetGainInput,.dryGainInput,.delayGainInput,.feedbackInput {
    margin-left: 15px;
}
.wetGain>p,.dryGain>p,.delayGain>p,.feedback>p {
    font-size: 10px;
}
.start, .stop {
    font-size:10px;
    font-weight:bold;
    text-decoration:none;
    display:block;
    text-align:center;
    padding:6px 23px;
    color:#fff;
    background-color:#000000;
    border-radius:5px;
    float: left;
    margin-left: 10px;
}
.files {
    font-size: 10px;
    margin: 10px 10px;
}
.clear {
    overflow: hidden;
    zoom: 1;
}
#drop_zone {
    width: 320px;
    height: 100px;
    line-height: 100px;
    text-align: center;
    margin: 5px;
    border: dashed 3px #a9a9a9;
    border-radius: 5px;
    font-weight: bold;
    color: #a9a9a9;
    background-color: #f2f2f2;
}
#createButton {
    position: relative;
    left: 0;
    top: 0;
    font-size: 100px;
    color: #ffffff;
    margin: 0 10px 0 0;
    padding: 0px;
    float: left;
}
#createButton:hover {
    cursor:pointer;
}
#checkSource {
    position: relative;
    left: 0;
    top: 0;
    font-size: 100px;
    color: #ffffff;
    margin: 0 10px 0 0;
    padding: 0px;
}
#checkSource:hover {
    cursor:pointer;
}
コードが長くなってしまいすみません。
WebAudioAPIをクラス化し、スライドバーを調節して得た値をインスタンス化したメンバ変数にセットして呼び出し、確認するコードです。
本来は音声の再生と停止のためにsourceNodeやそれぞれのNodeを繋ぐコードがありますが、長くなるので今回はGainを調節するコードのみです。

四角いPlusアイコンでインスタンスを生成し、配列にプッシュします。
虫眼鏡アイコンでスライドバーで調節したメンバ変数の値を確認できます。

前置きが長くなりましたが、困っていることは
2つ以上のインスタンスを生成した時、それぞれスライドバーで値を調節した後、虫眼鏡アイコンで確認すると、両方の値が変わってしまうことです。

そこでクラスからWebAudioAPIの要素を省いたシンプルなコードで実行しました。
一番始めにあるコードを下記のコードに丸々変更すると正常に動きます。

何故なのかどなたかアドバイスいただけないでしょうか?よろしくお願いします。
//Lineクラス
var Line = function(length){
    this.wetGainNode;
    this.lineNum;
    
    Line.prototype.init(length);
    
    console.log(
    '- WetGain' + this.wetGainNode
    );
}

Line.prototype.init = function(length){
    
    /* wetGain初期化 */
    this.wetGainNode = 0;
    
    /* LineContainer ModuleRoot要素の作成 */
    Line.prototype.createElem(Line.prototype.setLineNum(length));
}

Line.prototype.getWetGain = function(){
    return this.wetGainNode;
}

Line.prototype.setWetGain = function(val){
    this.wetGainNode = val;
}

Line.prototype.paramView = function(obj){
    console.log('wetGain : ' + obj.getWetGain());
}

Line.prototype.setLineNum = function(length){
    return this.lineNum = length;
}

Line.prototype.createElem = function(linenum){
    //HTML構造生成
    var pElem = document.querySelector('#lineContext');        //lineContext取得
    var lineContainer = document.createElement("div");                //lineContainer
        lineContainer.className = "lineContainer";
        lineContainer.setAttribute('data-linenum', linenum);
    /*-------------------------------wetGain-------------------------------*/
    //wetGainContainer
    var wetGainContainer = document.createElement("div");
    wetGainContainer.className = "wetGain";
    
    //h3
    var wetGain__p = document.createElement("p");
    wetGain__p.innerHTML = "wetGain";
    
    //wetGainView
    var wetGainView = document.createElement("div");
    wetGainView.className = "wetGainView";
    wetGainView.innerHTML = "0";
    
    //wetGain
    var wetGainInput = document.createElement("input");
    wetGainInput.className = "wetGainInput";
    wetGainInput.type = "range";
    wetGainInput.value = "0";
    wetGainInput.step = "1";
    wetGainInput.max = "100";
    /*----------------------------------------------------------------------*/
    
    
    
    /*----------------------------------------------------------------------*/
    
    /*-------------------------------appendChild----------------------------*/
    //wetGain - appendChild
    wetGainContainer.appendChild( wetGain__p );
    wetGainContainer.appendChild( wetGainView );
    wetGainContainer.appendChild( wetGainInput );
        
    //p - appendChild
    pElem.appendChild( lineContainer );
    lineContainer.appendChild( wetGainContainer );
    /*----------------------------------------------------------------------*/
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

テストコードのsetWetGainメソッドで
Line.prototype.setWetGain = function(val){
//    this.wetGainNode.gain.value = val;
    console.log(this.hasOwnProperty('wetGainNode'));
    console.log(this.wetGainNode);
    this.wetGainNode = val;
}
としてみると、1回目はfalse0になります。継承を参照していることになります。
2回目はtrueになりますので、1回目のsetWetGainメソッド実行で、プロパティを生やしていることになりますね。

ここでテストコードの初期化関数を、
Line.prototype.init = function(length){
    /* wetGain初期化 */
    this.wetGainNode = {gain:{value:0}};
    
    /* LineContainer ModuleRoot要素の作成 */
    Line.prototype.createElem(Line.prototype.setLineNum(length));
}
として変更して、本番コードのsetWetGain`getWetGain'を使ってみると、上手く動作しなくなります。
これは、setWetGainメソッドがwetGainNodeを書き換えずに、wetGainNode.gain.valueという継承されたオブジェクトを操作し続けるからです。



つまり、ひとことでいうと、thisが想定しているものを差していないのだと思います。



解決方法としては、
var Line = function(length){
    this.audioContext
    this.wetGainNode;
    this.lineNum;
    
    var webAudioAPI = (window.AudioContext ||
        window.webkitAudioContext ||
        window.mozAudioContext ||
        window.oAudioContext ||
        window.msAudioContext);
        
    /* 外部クラスインスタンス化 */
    this.audioContext = new webAudioAPI();

    /* 各種ノード生成 */
    this.wetGainNode = this.audioContext.createGain();    //wetGainNode
    
    /* wetGain初期化 */
    this.wetGainNode.gain.value = 0;
    
    /* LineContainer ModuleRoot要素の作成 */
    Line.prototype.createElem(Line.prototype.setLineNum(length));

}
などとして、初期化関数をコンストラクタの中に入れてしまうのが分かりやすいのではないかと思います。動作は確認していませんので、それで全て解決するとは限らないのですが……

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る