Trabajo con sonido generado dinámicamente

Flash Player 10 y posterior, Adobe AIR 1.5 y posterior

Nota: la posibilidad de generar audio dinámicamente está presente a partir de Flash Player 10 y Adobe AIR 1.5.

En lugar de cargar o transmitir un sonido existente, se pueden generar dinámicamente los datos de audio. Puede generar datos de audio cuando se asigna un detector de eventos para el evento sampleData de un objeto Sound. (El evento sampleData se define en la clase SampleDataEvent en el paquete flash.events.) En este entorno, el objeto Sound no carga datos de sonido desde un archivo. Actúa como socket para datos de sonido transmitidos en flujo mediante la función asignada al evento.

Cuando se añade un detector de eventos sampleData a un objeto Sound, el objeto solicita datos periódicamente para agregarlos al búfer de sonido. Este búfer contiene datos para el objeto Sound que se va a reproducir. Cuando se llama al método play() del objeto Sound, se distribuye el evento sampleData al solicitar nuevos datos de sonido. (El valor es true solo cuando el objeto Sound no ha cargado datos mp3 desde un archivo.)

El objeto SampleDataEvent incluye una propiedad data . En el detector de eventos, los objetos ByteArray se escriben en este objeto data . Los conjuntos de bytes en los que se escribe este objeto se añaden a los datos de sonido almacenados en búfer que reproduce el objeto Sound. El conjunto de bytes en el búfer es un flujo de valores de coma flotante de -1 a 1. Cada valor de coma flotante representa al amplitud de un canal (izquierdo o derecho) de una muestra de sonido. El sonido se muestrea a 44.100 muestras por segundo. Cada muestra contiene un canal izquierdo y derecho, intercalada como datos de coma flotante en el conjunto de bytes.

En la función de controlador, se utiliza el método ByteArray.writeFloat() para escribir en la propiedad data del evento sampleData . Por ejemplo, el siguiente código genera una onda de seno:

var mySound:Sound = new Sound(); 
mySound.addEventListener(SampleDataEvent.SAMPLE_DATA, sineWaveGenerator); 
mySound.play(); 
function sineWaveGenerator(event:SampleDataEvent):void 
{ 
    for (var i:int = 0; i < 8192; i++) 
    { 
        var n:Number = Math.sin((i + event.position) / Math.PI / 4); 
        event.data.writeFloat(n); 
        event.data.writeFloat(n); 
    } 
}

Cuando se llama a Sound.play() , la aplicación inicia la llamada al controlador de eventos, solicitando los datos de la muestra de sonido. La aplicación continúa enviando eventos a medida que se reproduce el sonido hasta que se detiene el suministro o se llama a SoundChannel.stop() .

La latencia del evento varía en función de la plataforma y puede cambiar en futuras versiones de Flash Player y AIR. No dependa de una latencia concreta: calcúlela. Para calcular la latencia, utilice la siguiente fórmula:

(SampleDataEvent.position / 44.1) - SoundChannelObject.position

Proporcione de 2048 hasta 8192 muestras a la propiedad data del objeto SampleDataEvent (para cada llamada al controlador de eventos). Para obtener el mejor rendimiento, proporcione tantas muestras como sea posible (hasta 8192). Cuanto menor sea el número de muestras, más probable será la aparición de interferencias en la reproducción. Este comportamiento puede variar en función de la plataforma y según las situaciones; por ejemplo, al cambiar de tamaño la ventana del navegador. El código que funciona en una plataforma cuando solo se proporcionan 2048 muestras puede que no funcione tan bien cuando se ejecuta en una plataforma distinta. Si necesita la menor latencia posible, considere la posibilidad de que sea el usuario quien seleccione la cantidad de datos.

Si se proporcionan menos de 2048 muestras (por llamada al detector de eventos sampleData ), la aplicación se detiene tras reproducir las muestras restantes. El objeto SoundChannel distribuye entonces un evento SoundComplete.

Modificación de sonido desde datos mp3

El método Sound.extract() se utiliza para extraer datos de un objeto Sound. Puede utilizar (y modificar) los datos para escribir en el flujo dinámico de otro objeto Sound para la reproducción. Por ejemplo, el siguiente código utiliza los bytes de archivo MP3 cargado y los transmite mediante una función de filtro, upOctave() :

var mySound:Sound = new Sound(); 
var sourceSnd:Sound = new Sound(); 
var urlReq:URLRequest = new URLRequest("test.mp3"); 
sourceSnd.load(urlReq); 
sourceSnd.addEventListener(Event.COMPLETE, loaded); 
function loaded(event:Event):void 
{ 
    mySound.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound); 
    mySound.play(); 
} 
function processSound(event:SampleDataEvent):void 
{ 
        var bytes:ByteArray = new ByteArray(); 
        sourceSnd.extract(bytes, 8192); 
        event.data.writeBytes(upOctave(bytes)); 
} 
function upOctave(bytes:ByteArray):ByteArray 
{ 
    var returnBytes:ByteArray = new ByteArray(); 
    bytes.position = 0; 
    while(bytes.bytesAvailable > 0) 
    { 
        returnBytes.writeFloat(bytes.readFloat()); 
        returnBytes.writeFloat(bytes.readFloat()); 
        if (bytes.bytesAvailable > 0) 
        { 
            bytes.position += 8; 
        } 
    } 
    return returnBytes; 
}

Limitaciones en los sonidos generados

Cuando se utiliza un detector de eventos sampleData con un objeto Sound, los únicos métodos de Sound que permanecen activados son Sound.extract() y Sound.play() . Llamar a otros métodos o propiedades genera una excepción. Todos los métodos y propiedades del objeto SoundChannel siguen activados.