What is the Three.Face3 in viewer.impl.hitTestViewport returned object? - autodesk

What is the Three.face in the object returned by viewer.impl.hitTestViewport()?
Here's an example:
What does it represent?

Just look at the source code in the three.js viewer implementation at line #8228.
// File:src/core/Face3.js
/**
* #author mrdoob / http://mrdoob.com/
* #author alteredq / http://alteredqualia.com/
*/
THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {
this.a = a;
this.b = b;
this.c = c;
this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
this.vertexNormals = normal instanceof Array ? normal : [];
this.color = color instanceof THREE.Color ? color : new THREE.Color();
this.vertexColors = color instanceof Array ? color : [];
this.vertexTangents = [];
this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
};
THREE.Face3.prototype = {
constructor: THREE.Face3,
clone: function () {
var face = new THREE.Face3( this.a, this.b, this.c );
face.normal.copy( this.normal );
face.color.copy( this.color );
face.materialIndex = this.materialIndex;
for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) {
face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
}
for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) {
face.vertexColors[ i ] = this.vertexColors[ i ].clone();
}
for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) {
face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
}
return face;
}
};
Take also a look at the three.js Face3 documentation:
Triangular face used in Geometry. These are created automatically for all standard geometry types, however if you are building a custom geometry you will have to create them manually.

I cannot answer that off-hand. What I can say with certainty, however, is how to implement ray tracing in the viewer, i.e., how to define a ray to be shot and how to determine the three.js objects intersected by it in the Forge model. This is demonstrated by the ForgeFader project on GitHub:
https://github.com/jeremytammik/forgefader

Related

Picking under elements of an element in Autodesk Forge viewer

I would like to accomplish a feature that I can do in Three.js but cannot in Autodesk Forge viewer. Here is the link to test: http://app.netonapp.com/JavaScript/Three.js/select_inner_objects.html
The requirement is to select objects inside an object. This job can be done with THREE.Raycaster in the above demo, to use a raycaster to detect all elements which are on the line the ray going through. Then I can get objects behind or inner another object.
I tried this concept in Autodesk Forge viewer but having no success. Here is the code:
// Change this to:
// true to use original Three.js
// false to use Autodesk Forge Viewer API
var useThreeJS = true;
var container = $('div.canvas-wrap')[0];
container.addEventListener('mousedown', function (event) {
if (useThreeJS) {
var canvas = _viewer.impl.canvas;
var containerWidth = canvas.clientWidth;
var containerHeight = canvas.clientHeight;
var camera = _viewer.getCamera();
var mouse = mouse || new THREE.Vector3();
var raycaster = raycaster || new THREE.Raycaster();
mouse.x = 2 * (event.clientX / containerWidth) - 1;
mouse.y = 1 - 2 * (event.clientY / containerHeight);
mouse.unproject(camera);
raycaster.set(camera.position, mouse.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects);
if (intersects.length == 1) {
var obj = intersects[0].object;
obj.material.color.setRGB(1.0 - i / intersects.length, 0, 0);
} else if (intersects.length > 1) {
// Exclude the first which is the outer object (i == 0)
for (var i = 1; i < intersects.length; i++) {
var obj = intersects[i].object;
obj.material.color.setRGB(1.0 - i / intersects.length, 0, 0);
}
}
} else {
var vp = _viewer.impl.clientToViewport(event.canvasX, event.canvasY);
var renderer = _viewer.impl.renderer();
var dbId = renderer.idAtPixel(vp.x, vp.y);
if (dbId) {
console.debug("Selected Id: " + dbId);
_viewer.select(dbId);
_viewer.impl.invalidate(true);
}
}
}, false);
I found the Forge viewer has viewer.impl.renderer().idAtPixel method which is great to get an element at the picking pixel. However, I want it to do more, to select all elements (which are under or nested) at the picking pixel. How I can do it with the Forge Viewer API?
Based on the suggestion of Zhong Wu in another post, here is the final solution to select element which is under or inside another element. I created an Autodesk Forge viewer extension to use it easily.
///////////////////////////////////////////////////////////////////////////////
// InnerSelection viewer extension
// by Khoa Ho, December 2016
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN.Viewing.Extension");
Autodesk.ADN.Viewing.Extension.InnerSelection = function (viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
var _self = this;
var _container = viewer.canvas.parentElement;
var _renderer = viewer.impl.renderer();
var _instanceTree = viewer.model.getData().instanceTree;
var _fragmentList = viewer.model.getFragmentList();
var _eventSelectionChanged = false;
var _viewport;
var _outerDbId;
_self.load = function () {
_container.addEventListener('mousedown',
onMouseDown);
viewer.addEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
onItemSelected);
console.log('Autodesk.ADN.Viewing.Extension.InnerSelection loaded');
return true;
};
_self.unload = function () {
_container.removeEventListener('mousedown',
onMouseDown);
viewer.removeEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
onItemSelected);
console.log('Autodesk.ADN.Viewing.Extension.InnerSelection unloaded');
return true;
};
function onMouseDown(e) {
var viewport = viewer.impl.clientToViewport(e.canvasX, e.canvasY);
_viewport = viewport; // Keep this viewport to use in onItemSelected()
var dbId = _renderer.idAtPixel(viewport.x, viewport.y);
if (_outerDbId == dbId) {
_outerDbId = -1;
// Deselect everything
viewer.select();
} else {
_outerDbId = dbId;
// Hide outer element temporarily to allow picking its behind element
viewer.hideById(dbId);
_eventSelectionChanged = true;
}
viewer.impl.sceneUpdated(true);
}
function onItemSelected(e) {
if (_eventSelectionChanged) {
// Prevent self looping on selection
_eventSelectionChanged = false;
// Show outer element back
viewer.show(_outerDbId);
// Get inner element Id after the outer element
// was just hidden on mouse down event
var innerDbId = _renderer.idAtPixel(_viewport.x, _viewport.y);
if (innerDbId > -1) {
// Select the inner element when it is found
viewer.select(innerDbId);
console.debug("Selected inner Id: " + innerDbId);
} else if (_outerDbId > -1) {
// Select the outer element if the inner element is not found
viewer.select(_outerDbId);
console.debug("Selected outer Id: " + _outerDbId);
}
}
}
};
Autodesk.ADN.Viewing.Extension.InnerSelection.prototype =
Object.create(Autodesk.Viewing.Extension.prototype);
Autodesk.ADN.Viewing.Extension.InnerSelection.prototype.constructor =
Autodesk.ADN.Viewing.Extension.InnerSelection;
Autodesk.Viewing.theExtensionManager.registerExtension(
'Autodesk.ADN.Viewing.Extension.InnerSelection',
Autodesk.ADN.Viewing.Extension.InnerSelection);
As of now (Dec/16), when you select using mouse click, the Viewer will not ignore transparent elements, so it will select an element even if it is transparent. Below is a code I used to track what's under the cursor, maybe can be useful.
// use jQuery to bind a mouve move event
$(_viewer.container).bind("mousemove", onMouseMove);
function onMouseMove(e) {
var screenPoint = {
x: event.clientX,
y: event.clientY
};
var n = normalize(screenPoint);
var dbId = /*_viewer.utilities.getHitPoint*/ getHitDbId(n.x, n.y);
//
// use the dbId somehow...
//
}
// This is a built-in method getHitPoint, but the original returns
// the hit point, so this modified version returns the dbId
function getHitDbId(){
y = 1.0 - y;
x = x * 2.0 - 1.0;
y = y * 2.0 - 1.0;
var vpVec = new THREE.Vector3(x, y, 1);
var result = _viewer.impl.hitTestViewport(vpVec, false);
//return result ? result.intersectPoint : null; // original implementation
return result ? result.dbId : null;
}
function normalize(screenPoint) {
var viewport = _viewer.navigation.getScreenViewport();
var n = {
x: (screenPoint.x - viewport.left) / viewport.width,
y: (screenPoint.y - viewport.top) / viewport.height
};
return n;
}
I see method viewer.impl.renderer().idAtPixel works better than viewer.impl.hitTestViewport to select element on mouse pick. The first one can click through the hidden/ghost element to get the objectId of element behind. While the second cannot. Here is the code to test:
var container = $('div.canvas-wrap')[0];
container.addEventListener('mousedown', function (event) {
var clickThroughHiddenElement = true;
if (clickThroughHiddenElement) {
var vp = _viewer.impl.clientToViewport(event.canvasX, event.canvasY);
var renderer = _viewer.impl.renderer();
var dbId = renderer.idAtPixel(vp.x, vp.y);
if (!!dbId) {
_viewer.select(dbId);
}
console.debug("Selected Id: " + dbId);
} else {
var screenPoint = {
x: event.clientX,
y: event.clientY
};
var viewport = _viewer.navigation.getScreenViewport();
var x = (screenPoint.x - viewport.left) / viewport.width;
var y = (screenPoint.y - viewport.top) / viewport.height;
// Normalize point
x = x * 2.0 - 1.0;
y = (1.0 - y) * 2.0 - 1.0;
var vpVec = new THREE.Vector3(x, y, 1);
var result = _viewer.impl.hitTestViewport(vpVec, false);
if (!!result) {
var dbId = result.dbId;
_viewer.select(dbId);
console.debug("Selected Id: " + dbId);
}
}
}
However, they are not what I want, to click through transparent element to get elements behind. If user selects transparent element, it will be selected. If user selects inner elements, it will ignore outer transparent element to select the pick inner element.
I check Forge viewer uses THREE.Raycaster with element bounding box to detect intersection on mouse click. It seems my problem is doable with the Forge viewer like it does in my Three.js demo.

AS3: How do I automate declaring multiple objects

I am trying to initialize and populate multiple objects along with their related properies automatically.
Basically I have a 32x32 grid and for each position on the grid I would like to assign an object with multiple properties that can be referenced later.
A 32x32 grid has 1024 positions on it and I really don't want to have to write up that many variable declarations manually. I have the array set up in a separate class file which allows me to assign a variable to a grid position: gridPos.put(x, y, object.property);
I have also set up a pair of for loops which will populate the objects with default starting data.
Now what I need to do is get it to declare the objects for me with unique names and then populate them all with the starting data. These objects need to be accessible from other parts of the code (I tried to declare them as public var gridPosTile[h] : Object = new Object; but declaring it as 'public' it gave me an error saying it "1114: The public attribute can only be used inside a package.")
*Also, I know [h] is not right but it was kinda how I saw it working in my head... please illuminate me :)
Many Thanks
public function gridPosTilePopulate():void
{
var g: int = 40;
var h: int = 1;
for(var i:int = 0; i < 32; i++)
{
var v: int = 40;
g += 40;
for(var q:int = 0; q < 32; q++)
{
var gridPosTile[h] : Object = new Object;
gridPos.put(i, q, gridPosTile[h]);
gridPosTile[h].xPos = (v + 40));
gridPosTile[h].yPos = (g + 40));
gridPosTile[h].p1Set = false);
gridPosTile[h].p2Set = false);
gridPosTile[h].m1Set = false);
gridPosTile[h].m2Set = false);
gridPosTile[h].m3Set = false);
gridPosTile[h].m4Set = false);
gridPosTile[h].coinSet = false);
gridPosTile[h].powerupSet = false);
v += 40;
h++;
}
}
}
You didn't post your full class so I can not tell you why you got the 1114 error.
I would start with adding a a property to your class to store the gridPosTitle objects.
You should use an array collection or a vector. In my example I will use an arrayCollection.
This storage collection will allow you easy reference to all of the tiles you have created.
To add a dynamic name property all you need to do is use bracket notation.
And lastly remove all reference to "h" since it is not needed except to name the object.
package com.example{
public class SomeClassName{
// storage var for future use.
public var tileStorage:ArrayColelction
public function gridPosTilePopulate():void
{
tileStorage = new ArrayCollection()
var g: int = 40;
var h: int = 1;
for(var i:int = 0; i < 32; i++)
{
var v: int = 40;
g += 40;
for(var q:int = 0; q < 32; q++)
{
var gridPosTile : Object = new Object;
gridPos.put(i, q, gridPosTile);
gridPosTile.xPos = (v + 40));
gridPosTile.yPos = (g + 40));
gridPosTile.p1Set = false);
gridPosTile.p2Set = false);
gridPosTile.m1Set = false);
gridPosTile.m2Set = false);
gridPosTile.m3Set = false);
gridPosTile.m4Set = false);
gridPosTile.coinSet = false);
gridPosTile.powerupSet = false);
v += 40;
h++;
// here we add the name property
// try to never use keywords on dynamic classes since sometimes they may already be used
gridPosTile.myName = "tile_" + h;
tileStorage.additem(gridPosTile)
}
}
}
}
}

As3 how to call and use an external class

I have this cool As3 MP3pitch package, which I got from here: http://blog.andre-michelle.com/2009/pitch-mp3/#more-483
package components
{
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.ByteArray;
/**
* #author Andre Michelle (andre.michelle#gmail.com)
*/
public class MP3Pitch
{
private const BLOCK_SIZE: int = 3072;
private var _mp3: Sound;
private var _sound: Sound;
private var _target: ByteArray;
private var _position: Number;
private var _rate: Number;
public function MP3Pitch( url: String )
{
_target = new ByteArray();
_mp3 = new Sound();
_mp3.addEventListener( Event.COMPLETE, complete );
_mp3.load( new URLRequest( url ) );
_position = 0.0;
_rate = 1.0;
_sound = new Sound();
_sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
}
public function get rate(): Number
{
return _rate;
}
public function set rate( value: Number ): void
{
if( value < 0.0 )
value = 0;
_rate = value;
}
private function complete( event: Event ): void
{
_sound.play();
}
private function sampleData( event: SampleDataEvent ): void
{
//-- REUSE INSTEAD OF RECREATION
_target.position = 0;
//-- SHORTCUT
var data: ByteArray = event.data;
var scaledBlockSize: Number = BLOCK_SIZE * _rate;
var positionInt: int = _position;
var alpha: Number = _position - positionInt;
var positionTargetNum: Number = alpha;
var positionTargetInt: int = -1;
//-- COMPUTE NUMBER OF SAMPLES NEED TO PROCESS BLOCK (+2 FOR INTERPOLATION)
var need: int = Math.ceil( scaledBlockSize ) + 2;
//-- EXTRACT SAMPLES
var read: int = _mp3.extract( _target, need, positionInt );
var n: int = read == need ? BLOCK_SIZE : read / _rate;
var l0: Number;
var r0: Number;
var l1: Number;
var r1: Number;
for( var i: int = 0 ; i < n ; ++i )
{
//-- AVOID READING EQUAL SAMPLES, IF RATE < 1.0
if( int( positionTargetNum ) != positionTargetInt )
{
positionTargetInt = positionTargetNum;
//-- SET TARGET READ POSITION
_target.position = positionTargetInt << 3;
//-- READ TWO STEREO SAMPLES FOR LINEAR INTERPOLATION
l0 = _target.readFloat();
r0 = _target.readFloat();
l1 = _target.readFloat();
r1 = _target.readFloat();
}
//-- WRITE INTERPOLATED AMPLITUDES INTO STREAM
data.writeFloat( l0 + alpha * ( l1 - l0 ) );
data.writeFloat( r0 + alpha * ( r1 - r0 ) );
//-- INCREASE TARGET POSITION
positionTargetNum += _rate;
//-- INCREASE FRACTION AND CLAMP BETWEEN 0 AND 1
alpha += _rate;
while( alpha >= 1.0 ) --alpha;
}
//-- FILL REST OF STREAM WITH ZEROs
if( i < BLOCK_SIZE )
{
while( i < BLOCK_SIZE )
{
data.writeFloat( 0.0 );
data.writeFloat( 0.0 );
++i;
}
}
//-- INCREASE SOUND POSITION
_position += scaledBlockSize;
}
}
}
How can I include it into my "main" as3 file and use it? I can't just slap it into the same file, since the main file already has it's own package and class.
Essentially what I'm trying to do here is to load a sound file, play it, and change it's pitch in relation to the values what I have already.
Thanks in advance.
You have to create a folder with the same name as the package (here components) and put this class in it. Then from your main, import this class:
import components.MP3Pitch
You just have to instanciate this class and use it in your code:
var pitcher:MP3Pitch = new MP3Pitch("mymp3.mp3");
pitcher.rate = 2;
package {
import components.MP3Pitch;
public class Main extends Sprite
{
public function Main() {
new MP3Pitch("http://path-to-mp3-file.com/");
}
}
}

how to trace "depth" or stacking order of a display object?

How can you trace the "depth" or stacking order of a display object with AS3?
I'm trying to figure out if my sprite is behind another sprite...
container.getChildIndex(displayObject);
but that will only tell you how deep it is, not necessarily if anything is in front of it.
Function comparing two DisplayObject instances to determine which one is at a higher "depth" on the display list:
private function higher(a:DisplayObject, b:DisplayObject):DisplayObject
{
// Parent chains
var ac:Array = [a];
var bc:Array = [b];
// Pointers to individual nodes
var an:DisplayObject = a.parent;
var bn:DisplayObject = b.parent;
while (an != null) {
ac.push(an);
an = an.parent;
}
while (bn != null) {
bc.push(bn);
bn = bn.parent;
}
var acl:int = ac.length;
var bcl:int = bc.length;
var n:int = Math.min(acl, bcl);
var i:int = 0;
for (; i < n; i++) {
an = ac[acl - i - 1];
bn = bc[bcl - i - 1];
// First uncommon ancestor
if (an != bn)
break;
}
var ca:DisplayObjectContainer = an.parent;
if (!ca)
return null;
if (ca.getChildIndex(an) > ca.getChildIndex(bn))
return a;
else
return b;
}
Note: If one of the objects is not on the display list, the function returns null. You can change it to return the other object instead.
You can almost certainly optimize this, but this is a first cut.
Just a refactored version of Manish answer using vectors and which won't return weird result if you ever call higher(a,a.parent).
parents() may be used for other purpose too :
public function higher(a:DisplayObject, b:DisplayObject):DisplayObject
{
var aParents:Vector.<DisplayObject> = parents(a);
var bParents:Vector.<DisplayObject> = parents(b);
var commonDepth:int = Math.min(aParents.length, bParents.length);
for (var depth:int = 0; depth < commonDepth; depth++)
if (aParents[depth] != bParents[depth])
break;
if (depth == 0 || depth == commonDepth)
return null;
var commonAncestor:DisplayObjectContainer = aParents[depth].parent;
if (commonAncestor.getChildIndex(aParents[depth]) > commonAncestor.getChildIndex(bParents[depth]))
return a;
else
return b;
}
private function parents(d:DisplayObject):Vector.<DisplayObject>
{
var result:Vector.<DisplayObject> = new Vector.<DisplayObject>;
while (d != null)
{
result.unshift(d);
d = d.parent;
}
return result;
}
private function getDepth(clip:DisplayObject):uint
{
var depth:uint = 0;
var currentClip:DisplayObject = clip;
while (currentClip.parent && currentClip.parent != this)
{
depth++;
currentClip = currentClip.parent;
}
return depth;
}
container.getChildIndex(child) should do it, it returns the index of the child
This is a revised version of what jauboux did from a version Manish did.
Namely, adding a null return value from highestOf() when depths match.
/**
* #param ifDepthsMatchReturnObjectA
* #return Whichever DisplayObject is higher on the display list.
* Optionally returns `null` if they're at the same depth.
*/
public function highestOf(a:DisplayObject, b:DisplayObject, ifDepthsMatchReturnObjectA:Boolean = false):DisplayObject
{
var aParents:Vector.<DisplayObject> = ancestorsOf(a);
var bParents:Vector.<DisplayObject> = ancestorsOf(b);
var commonDepth:int = Math.min(aParents.length, bParents.length);
for (var depth:int = 0; depth < commonDepth; depth++)
if (aParents[depth] != bParents[depth])
break;
if (depth == 0 || depth == commonDepth)
return null;
var commonAncestor:DisplayObjectContainer = aParents[depth].parent;
var aDepthOnCommonAncestor:int = commonAncestor.getChildIndex(aParents[depth]);
var bDepthOnCommonAncestor:int = commonAncestor.getChildIndex(bParents[depth]);
if (aDepthOnCommonAncestor > bDepthOnCommonAncestor)
return a;
else if (aDepthOnCommonAncestor < bDepthOnCommonAncestor)
return b;
else
return ifDepthsMatchReturnObjectA ? a : null;
}
/**
* #return Whether a is higher than b.
*/
public function isHigher(a:DisplayObject, b:DisplayObject):Boolean
{
return highestOf(a, b) === a;
}
/**
* #return All ancestors of given display.
*/
private function ancestorsOf(display:DisplayObject):Vector.<DisplayObject>
{
var result:Vector.<DisplayObject> = new Vector.<DisplayObject>;
while (display != null)
{
result.unshift(display);
display = display.parent;
}
return result;
}

Controlling Sound Pitch With Actionscript 3.0?

after browsing the documentation for the sound classes, it seems there is no way to control sound pitch with Actionscript 3.0. there is only the ability to control volume and pan. why is there no pitch property? it's the only sound property missing for the ability to create a full featured sound engine in Actionscript?
i hope i'm misinformed, but in case i'm not are there any alternatives / workarounds to control pitch in AS3?
Andre Michelle has a great article on Pitch control with actionscript 3.0
For reference, here is Andre's sample code:
package components
{
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.ByteArray;
/**
* #author Andre Michelle (andre.michelle#gmail.com)
*/
public class MP3Pitch
{
private const BLOCK_SIZE: int = 3072;
private var _mp3: Sound;
private var _sound: Sound;
private var _target: ByteArray;
private var _position: Number;
private var _rate: Number;
public function MP3Pitch( url: String )
{
_target = new ByteArray();
_mp3 = new Sound();
_mp3.addEventListener( Event.COMPLETE, complete );
_mp3.load( new URLRequest( url ) );
_position = 0.0;
_rate = 1.0;
_sound = new Sound();
_sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
}
public function get rate(): Number
{
return _rate;
}
public function set rate( value: Number ): void
{
if( value < 0.0 )
value = 0;
_rate = value;
}
private function complete( event: Event ): void
{
_sound.play();
}
private function sampleData( event: SampleDataEvent ): void
{
//-- REUSE INSTEAD OF RECREATION
_target.position = 0;
//-- SHORTCUT
var data: ByteArray = event.data;
var scaledBlockSize: Number = BLOCK_SIZE * _rate;
var positionInt: int = _position;
var alpha: Number = _position - positionInt;
var positionTargetNum: Number = alpha;
var positionTargetInt: int = -1;
//-- COMPUTE NUMBER OF SAMPLES NEED TO PROCESS BLOCK (+2 FOR INTERPOLATION)
var need: int = Math.ceil( scaledBlockSize ) + 2;
//-- EXTRACT SAMPLES
var read: int = _mp3.extract( _target, need, positionInt );
var n: int = read == need ? BLOCK_SIZE : read / _rate;
var l0: Number;
var r0: Number;
var l1: Number;
var r1: Number;
for( var i: int = 0 ; i < n ; ++i )
{
//-- AVOID READING EQUAL SAMPLES, IF RATE < 1.0
if( int( positionTargetNum ) != positionTargetInt )
{
positionTargetInt = positionTargetNum;
//-- SET TARGET READ POSITION
_target.position = positionTargetInt << 3;
//-- READ TWO STEREO SAMPLES FOR LINEAR INTERPOLATION
l0 = _target.readFloat();
r0 = _target.readFloat();
l1 = _target.readFloat();
r1 = _target.readFloat();
}
//-- WRITE INTERPOLATED AMPLITUDES INTO STREAM
data.writeFloat( l0 + alpha * ( l1 - l0 ) );
data.writeFloat( r0 + alpha * ( r1 - r0 ) );
//-- INCREASE TARGET POSITION
positionTargetNum += _rate;
//-- INCREASE FRACTION AND CLAMP BETWEEN 0 AND 1
alpha += _rate;
while( alpha >= 1.0 ) --alpha;
}
//-- FILL REST OF STREAM WITH ZEROs
if( i < BLOCK_SIZE )
{
while( i < BLOCK_SIZE )
{
data.writeFloat( 0.0 );
data.writeFloat( 0.0 );
++i;
}
}
//-- INCREASE SOUND POSITION
_position += scaledBlockSize;
}
}
}
Basic usage would be something like:
//create an MP3Pitch instance and load a sound
var mp3:MP3Pitch = new MP3Pitch("/path/to/your/file.mp3");
//change the pitch via rate setter
mp3.rate += 0.5
Extract a bytearray from the sound object, and then manipulate the byte data, returning a new bytearray.
Here is the actual example from the API Reference Doc
var sourceSnd:Sound = new Sound();
var outputSnd:Sound = new Sound();
var urlReq:URLRequest = new URLRequest("test.mp3");
sourceSnd.load(urlReq); sourceSnd.addEventListener(Event.COMPLETE, loaded);
function loaded(event:Event):void {
outputSnd.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
outputSnd.play(); }
function processSound(event:SampleDataEvent):void {
var bytes:ByteArray = new ByteArray();
sourceSnd.extract(bytes, 4096);
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;
}