package org.geogebra.web.html5.sound; import org.geogebra.web.html5.Browser; import com.google.gwt.core.client.JavaScriptObject; public class WebAudioWrapper { public interface FunctionAudioListener { double getValueAt(double t); } public static final WebAudioWrapper INSTANCE = new WebAudioWrapper(); private FunctionAudioListener listener = null; private boolean supported; private static double time; private static double deltaTime; private static double stopTime; private static JavaScriptObject context; private static JavaScriptObject processor; private WebAudioWrapper() { supported = !Browser.isIE() && !Browser.isFirefox(); init(); } public native boolean init() /*-{ if (!this.@org.geogebra.web.html5.sound.WebAudioWrapper::isSupported()()) { return false; } var contextClass = ($wnd.AudioContext || $wnd.webkitAudioContext || $wnd.mozAudioContext || $wnd.oAudioContext || $wnd.msAudioContext); if (contextClass) { // Web Audio API is available. @org.geogebra.web.html5.sound.WebAudioWrapper::context = new contextClass(); @org.geogebra.web.html5.sound.WebAudioWrapper::deltaTime = 1 / @org.geogebra.web.html5.sound.WebAudioWrapper::context.sampleRate; @org.geogebra.web.html5.sound.WebAudioWrapper::processor = @org.geogebra.web.html5.sound.WebAudioWrapper::context.createScriptProcessor(2048, 0, 1); @org.geogebra.web.html5.sound.WebAudioWrapper::processor.onaudioprocess = @org.geogebra.web.html5.sound.WebAudioWrapper::onAudioProcess(Lcom/google/gwt/core/client/JavaScriptObject;); return true; } else { return false; } }-*/; public native void start(double min, double max, int sampleRate) /*-{ if (!this.@org.geogebra.web.html5.sound.WebAudioWrapper::isSupported()()) { return; } // TODO: use sampleRate somehow as well @org.geogebra.web.html5.sound.WebAudioWrapper::time = min; @org.geogebra.web.html5.sound.WebAudioWrapper::stopTime = max; @org.geogebra.web.html5.sound.WebAudioWrapper::processor .connect(@org.geogebra.web.html5.sound.WebAudioWrapper::context.destination); }-*/; /** * Gets the value of a sound function at given time * * @param t * the time for function value * @return the sound value. */ public double getValueAt(double t) { return listener.getValueAt(t); } private static native void onAudioProcess(JavaScriptObject e) /*-{ var data = e.outputBuffer.getChannelData(0); for (var i = 0; i < data.length; i++) { data[i] = @org.geogebra.web.html5.sound.WebAudioWrapper::INSTANCE .@org.geogebra.web.html5.sound.WebAudioWrapper::getValueAt( D) (@org.geogebra.web.html5.sound.WebAudioWrapper::time); @org.geogebra.web.html5.sound.WebAudioWrapper::time = @org.geogebra.web.html5.sound.WebAudioWrapper::time + @org.geogebra.web.html5.sound.WebAudioWrapper::deltaTime; } if (@org.geogebra.web.html5.sound.WebAudioWrapper::time >= @org.geogebra.web.html5.sound.WebAudioWrapper::stopTime) { @org.geogebra.web.html5.sound.WebAudioWrapper::INSTANCE.@org.geogebra.web.html5.sound.WebAudioWrapper::stop()(); } }-*/; public native void stop() /*-{ if (!this.@org.geogebra.web.html5.sound.WebAudioWrapper::isSupported()()) { return; } @org.geogebra.web.html5.sound.WebAudioWrapper::processor.disconnect(); }-*/; public FunctionAudioListener getListener() { return listener; } public void setListener(FunctionAudioListener listener) { this.listener = listener; } public boolean isSupported() { return supported; } }