Gilles De Truchis
Qu'il me soit permis de m'éloigner un peu de la finance et de présenter, dans un registre bien plus léger, un tutoriel sur l'utilisation des nouvelles fonctionnalités de la classe Sound sous le
flash player 10.
Les développeurs AS3 que vous êtes auront bien-sûr constaté que la classe Sound diffuse, depuis la sortie de flash player 10, un nouvel événement: SampleData. Cet événement est distribué lorsque le lecteur demande de nouvelles données audio et permet de gérer le son généré dynamiquement ou lu. Dans cet environnement, l'objet Sound ne contient pas vraiment de données
audio. Il agit en fait en tant que socket pour les données audio qui lui sont distribuées en continu par l'intermédiaire de la fonction écouteur. On va ainsi être en mesure de collecter, via des
BytesArray, des échantillons du son généré ou lu. Le flash player 10 inclus parmi ses nouveautés une nouvelle fonctionnalité qui manquait cruellement aux anciennes versions: la méthode
FileReference.save( data:*, defaultFileName:String = null). Les données collectées, qui en cet
instant sont au format RAW (Real Audio Wrapper), vont alors pouvoir être encodées puis écrites en dur, via cette méthode, sur le disque. Pour plus de précision sur le format des données, on
pourra se tourner vers les PCM (Modulation d'impulsion codée). Enfin présentons la méthode star de ce tutoriel: Sound.extract(target:ByteArray, length:Number, startPosition:Number = -1):Number. Cette méthode doit être employée
lorsque l'on gére un son généré dynamiquement ou lu, à l'aide d'une fonction que l'on affecte à l'événement SampleData pour un autre objet Sound. En d'autres termes, on va utiliser cette méthode pour extraire les données audio d'un objet Sound. Le flash player autorise un fourchette pour le nombre
d'échantillons à fournir: [2048, 8192]. La qualité sera bien-sûr maximal avec 8192.
Pour commencer, nous allons déclarer les objets dont nous avons besoins:
var sound:Sound = new Sound();
var dynamicSound:Sound = new Sound();
var soundChannel:SoundChannel = new SoundChannel();
var samples:ByteArray = new ByteArray();
var sndBytes:ByteArray = new ByteArray();
var myFileRefSave:FileReference = new FileReference();
Sur la scène nous disposons de 2 boutons, l'un de label "Record" et d'occurence "record" sert à lancer le son et collecter les échantillons et l'autre de label "Save" et d'occurence "save" sert à
appeler la méthode save de FileReference.
record.addEventListener( MouseEvent.MOUSE_DOWN, startRecord );
function startRecord( pEvt:MouseEvent )
{
sound = new Track();
dynamicSound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
soundChannel = dynamicSound.play();
save.addEventListener( MouseEvent.MOUSE_DOWN, stopRecord );
}
function sampleData( pEvt:SampleDataEvent ):void
{
samples.position = 0;
var len:Number = sound.extract( samples, 8192 );
var left:Number;
var right:Number;
samples.position = 0;
sndBytes.writeBytes( samples );
for ( var c:int=0; c < len; c++ )
{
left = samples.readFloat();
right = samples.readFloat();
pEvt.data.writeFloat( left );
pEvt.data.writeFloat( right );
}
}
function stopRecord( pEvt:MouseEvent )
{
myFileRefSave.save( FxWaveEncoder.encoder( sndBytes ), "snd.wav" );
}
Notons que Track est le nom de classe (ou liaison pour les anciens d'AS2) d'un son placé dans la librairie.
Avant d'être écrit on converti le son via la méthode static:
FxWaveEncoder.encoder( pSamples:ByteArray, channels:int = 2, bits:int = 16, rate:int = 44100 ):ByteArray
Voici la classe FxWaveEncoder qui permet d'encoder le format. Je remercie les membres de Médiabox qui m'ont aidé à calibrer cette
classe:
package
{
import flash.utils.Endian;
import flash.utils.ByteArray;
import flash.events.Event;
public class FxWaveEncoder
{
// writeHeader ( 2, 16, 44100 )
static public function encoder( pSamples:ByteArray, channels:int = 2, bits:int = 16, rate:int = 44100 ):ByteArray
{
var samples:ByteArray = new ByteArray();
samples.writeBytes( FxWaveEncoder.convert( pSamples ) );
var bytes: ByteArray = new ByteArray();
bytes.endian = Endian.LITTLE_ENDIAN;
bytes.writeUTFBytes( 'RIFF' );
bytes.writeInt( samples.length - 8 );
bytes.writeUTFBytes( 'WAVE' );
bytes.writeUTFBytes( 'fmt ' );
bytes.writeInt( int( 16 ) );
bytes.writeShort( int( 1 ) );
bytes.writeShort( channels );
bytes.writeInt( rate );
bytes.writeInt( int( rate * channels * ( bits / 8 ) ) );
bytes.writeShort( int( channels * ( bits / 8 ) ) );
bytes.writeShort( bits );
bytes.writeUTFBytes( 'data' );
bytes.writeInt( samples.length - 44 );
bytes.writeBytes( samples );
bytes.position = 0;
return bytes;
}
static private function convert( pBytes:ByteArray ):ByteArray
{
var ba:ByteArray = new ByteArray ( ) ;
ba.endian = Endian.LITTLE_ENDIAN;
pBytes.position = 0;
while( pBytes.position < pBytes.length ) ba.writeShort( pBytes.readFloat() * 32767 );
return ba;
}
}
}
Pour les détails des chunks on pourra se référer aux liens de bas de page de cette article: WAVE
Ce n'est pas très sexy mais bien pratique.
Et voici le résultat:
Télécharger les sources