2013-11-10 6 views
10

Возможно ли реализовать пользовательский AudioNode с помощью API веб-аудио?Внедрение JavaScript AudioNode

Я хотел бы построить узел, который будет содержать несколько других узлов (ChannelSplitters и AnalyserNodes). В идеале я смогу подключиться к этому настраиваемому узлу, как и любой другой AudioNode. Например,

var customNode = new CustomNode(); 
mediaStreamSource = context.createMediaStreamSource(userMedia); 

// This will not work, as I need to know what to implement in CustomNode 
mediaStreamSource.connect(customNode); 
customNode.connect(context.destination); 

Согласно MDN documentation, AudioNode реализует EventTarget interface. Это все, что используется для перетасовки аудио? И если да, то каким образом можно реализовать этот интерфейс для обработки звука?

+0

возможно дубликат [Создание пользовательский эхо-узел с веб-аудио] (http://stackoverflow.com/questions/13702733/creating-a-custom-echo-node-with-web-audio) – idbehold

ответ

3

файл класса AudioNode

"use strict"; 

var AudioNode = global.AudioNode; 
var AudioNode$connect; 
var AudioNode$disconnect; 

function connect() { 
    var args = [].slice.call(arguments); 

    if (args.length && typeof args[0].__connectFrom === "function") { 
    args[0].__connectFrom.apply(args[0], [ this ].concat(args.slice(1))); 
    } else { 
    AudioNode$connect.apply(this, args); 
    } 
} 

function disconnect() { 
    var args = [].slice.call(arguments); 

    if (args.length && typeof args[0].__disconnectFrom === "function") { 
    args[0].__disconnectFrom.apply(args[0], [ this ].concat(args.slice(1))); 
    } else { 
    AudioNode$disconnect.apply(this, args); 
    } 
} 

function use() { 
    if (typeof AudioNode !== "undefined" && AudioNode.prototype.connect !== connect) { 
    AudioNode$connect = AudioNode.prototype.connect; 
    AudioNode$disconnect = AudioNode.prototype.disconnect; 

    AudioNode.prototype.connect = connect; 
    AudioNode.prototype.disconnect = disconnect; 
    } 
} 

function unuse() { 
    if (typeof AudioNode !== "undefined" && AudioNode.prototype.connect === connect) { 
    AudioNode.prototype.connect = AudioNode$connect; 
    AudioNode.prototype.disconnect = AudioNode$disconnect; 
    } 
} 

module.exports = { 
    use: use, 
    unuse: unuse, 
}; 

тест AudioNode файл

"use strict"; 

var assert = require("power-assert"); 
var PowerAudioNode = require("../"); 

function CustomAudioNode(audioContext) { 
    this.audioContext = audioContext; 
    this.gain1 = audioContext.createGain(); 
    this.gain2 = audioContext.createGain(); 
    this.inlet = this.gain1; 
    this.outlet = this.gain2; 
} 

CustomAudioNode.prototype.connect = function() { 
    this.gain1.connect(this.gain2); 
    this.gain2.connect.apply(this.gain2, arguments); 
}; 

CustomAudioNode.prototype.disconnect = function() { 
    this.gain1.disconnect(); 
    this.gain2.disconnect.apply(this.gain2, arguments); 
}; 

CustomAudioNode.prototype.__connectFrom = function(source) { 
    source.connect(this.gain1); 
}; 

CustomAudioNode.prototype.__disconnectFrom = function(source) { 
    source.disconnect(); 
}; 

describe("PowerAudioNode", function() { 
    describe("use(): void", function() { 
    before(PowerAudioNode.use); 
    before(PowerAudioNode.use); 
    it("works", function() { 
     var audioContext = new global.AudioContext(); 
     var oscillator = audioContext.createOscillator(); 
     var customAudioNode = new CustomAudioNode(audioContext); 
     var compressor = audioContext.createDynamicsCompressor(); 

     oscillator.connect(customAudioNode); 
     customAudioNode.connect(compressor); 
     compressor.connect(audioContext.destination); 

     assert(audioContext.destination.$isConnectedFrom(compressor)); 
     assert(compressor.$isConnectedFrom(customAudioNode.outlet)); 
     assert(customAudioNode.inlet.$isConnectedFrom(oscillator)); 

     oscillator.disconnect(customAudioNode); 
     customAudioNode.disconnect(); 
     compressor.disconnect(); 

     assert(!audioContext.destination.$isConnectedFrom(compressor)); 
     assert(!compressor.$isConnectedFrom(customAudioNode.outlet)); 
     assert(!customAudioNode.inlet.$isConnectedFrom(oscillator)); 
    }); 
    }); 
    describe("unuse(): void", function() { 
    before(PowerAudioNode.unuse); 
    it("works", function() { 
     var audioContext = new global.AudioContext(); 
     var oscillator = audioContext.createOscillator(); 
     var customAudioNode = new CustomAudioNode(audioContext); 
     var compressor = audioContext.createDynamicsCompressor(); 

     assert.throws(function() { 
     oscillator.connect(customAudioNode); 
     }); 
     customAudioNode.connect(compressor); 
     compressor.connect(audioContext.destination); 

     assert(audioContext.destination.$isConnectedFrom(compressor)); 
     assert(compressor.$isConnectedFrom(customAudioNode.outlet)); 
     assert(!customAudioNode.inlet.$isConnectedFrom(oscillator)); 

     oscillator.disconnect(); 
     customAudioNode.disconnect(); 
     compressor.disconnect(); 

     assert(!audioContext.destination.$isConnectedFrom(compressor)); 
     assert(!compressor.$isConnectedFrom(customAudioNode.outlet)); 
     assert(!customAudioNode.inlet.$isConnectedFrom(oscillator)); 
    }); 
    }); 
}); 
+0

Хорошая идея! Спасибо за сообщение. – Brad

+0

FYI, для кого-то любопытного, я нашел этот код в модуле здесь: https://github.com/mohayonao/power-audio-node @targunp Вы пишете это? Если нет, вы должны отдать должное оригинальному автору, mohayonao. – Brad

+0

И лучшая версия здесь: https://github.com/altnode/alt-audio-node – Brad

5

This article похоже, у вас есть способ сделать только то, что вы ищете.

Основная предпосылка:

function MyCustomNode(){ 
    this.input = audioContext.createGainNode(); 
    var output = audioContext.createGainNode(); 
    this.connect = function(target){ 
    output.connect(target); 
    }; 
} 

Пример:

function AudioBus(){ 
    this.input = audioContext.createGainNode(); 
    var output = audioContext.createGainNode(); 
    var custom = new MyCustomNode(); 

    this.input.connect(custom); 
    custom.connect(output); 

    this.connect = function(target){ 
    output.connect(target); 
    }; 
} 

//create some native oscillators and our custom audio bus 
var bus = new AudioBus(), 
    instrument1 = audioContext.createOscillator(), 
    instrument2 = audioContext.createOscillator(), 
    instrument3 = audioContext.createOscillator(); 

//connect our instruments to the same bus 
instrument1.connect(bus.input); 
instrument2.connect(bus.input); 
instrument3.connect(bus.input); 
bus.connect(audioContext.destination); 

Edit: Вопрос может быть возможным дубликатом Creating a custom echo node with web-audio, но я считаю, что ответ вы ищете это the one from @MattDiamond. Это не совсем довольно решение, но это, кажется, получить работу:

function FeedbackDelayNode(context, delay, feedback){ 
    this.delayTime.value = delay; 
    this.gainNode = context.createGainNode(); 
    this.gainNode.gain.value = feedback; 
    this.connect(this.gainNode); 
    this.gainNode.connect(this); 
} 

function FeedbackDelayFactory(context, delayTime, feedback){ 
    var delay = context.createDelayNode(delayTime + 1); 
    FeedbackDelayNode.call(delay, context, delayTime, feedback); 
    return delay; 
} 

AudioContext.prototype.createFeedbackDelay = function(delay, feedback){ 
    return FeedbackDelayFactory(this, delay, feedback); 
}; 
+1

Спасибо, это именно то, м делать сейчас. То, что я хотел бы сделать, это иметь настраиваемый узел, с которым другой узел может напрямую подключаться. В вашем примере я бы использовал 'instrument1.connect (bus)' вместо 'instrument1.connect (bus.input)'. Имеет ли это смысл? – Brad

+1

@ Брад да, я это полностью понимаю. Я играл с цепочкой прототипов «AudioNode», но независимо от того, как я пытался расширять ее, я всегда получал ошибки 'Illegal Invocation', когда бы я попытался объединить узлы вместе. Я бы сказал, что это невозможно, потому что все собственные типы «AudioNode» создаются с помощью экземпляра «AudioContext», создающего метод [* NodeType *]. Я бы предположил, что здесь происходит волшебство. – idbehold

+0

@Brad см. Мое редактирование. – idbehold

Смежные вопросы