Trouble creating a spectrogram - actionscript-3

I know it was asked a thousand times before, but I still can't find a solution.
Searching SO, I indeed found the algorithm for it, but lacking the mathematical knowledge required to truly understand it, I am helplessly lost!
To start with the beginning, my goal is to compute an entire spectrogram and save it to an image in order to use it for a visualizer.
I tried using Sound.computeSpectrum, but this requires to play the sound and wait for it to end, I want to compute the spectrogram in a way shorter time than that will require to listen all the song. And I have 2 hours long mp3s.
What I am doing now is to read the bytes from a Sound object, the separate into two Vectors(.); Then using a timer, at each 100 ms I call a function (step1) where I have the implementation of the algorithm, as follows:
for each vector (each for a channel) I apply the hann function to the elements;
for each vector I nullify the imaginary part (I have a secondary vector for that)
for each vector I apply FFT
for each vector I find the magnitude for the first N / 2 elements
for each vector I convert squared magnitude to dB scale
end.
But I get only negative values, and only 30 percent of the results might be useful (in the way that the rest are identical)
I will post the code for only one channel to get rid off the "for each vector" part.
private var N:Number = 512;
private function step1() : void
{
var xReLeft:Vector.<Number> = new Vector.<Number>(N);
var xImLeft:Vector.<Number> = new Vector.<Number>(N);
var leftA:Vector.<Number> = new Vector.<Number>(N);
// getting sample range
leftA = this.channels.left.slice(step * N, step * (N) + (N));
if (leftA.length < N)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
else if (leftA.length == 0)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
var i:int;
// hann window function init
m_win = new Vector.<Number>(N);
for ( var i:int = 0; i < N; i++ )
m_win[i] = (4.0 / N) * 0.5 * (1 - Math.cos(2 * Math.PI * i / N));
// applying hann window function
for ( i = 0; i < N; i++ )
{
xReLeft[i] = m_win[i]*leftA[i];
//xReRight[i] = m_win[i]*rightA[i];
}
// nullify the imaginary part
for ( i = 0; i < N; i++ )
{
xImLeft[i] = 0.0;
//xImRight[i] = 0.0;
}
var magnitutel:Vector.<Number> = new Vector.<Number>(N);
fftl.run( xReLeft, xImLeft );
current = xReLeft;
currf = xImLeft;
for ( i = 0; i < N / 2; i++ )
{
var re:Number = xReLeft[i];
var im:Number = xImLeft[i];
magnitutel[i] = Math.sqrt(re * re + im * im);
}
const SCALE:Number = 20 / Math.LN10;
var l:uint = this.total.length;
for ( i = 0; i < N / 2; i++ )
{
magnitutel[i] = SCALE * Math.log( magnitutel[i] + Number.MIN_VALUE );
}
var bufferl:Vector.<Number> = new Vector.<Number>();
for (i = 0; i < N / 2 ; i++)
{
bufferl[i] = magnitutel[i];
}
var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
complete[0] = bufferl;
this.total[step] = complete;
this.step++;
}
This function is executed in the event dispatched by the timer (stepper).
Obviously I do something wrong, as I said I have only negative values and further more values range between 1 and 7000 (at least).
I want to thank you in advance for any help.
With respect,
Paul

Negative dB values are OK. Just add a constant (representing your volume control) until the number of points you want to color become positive. The remaining values that stay negative are usually just displayed or colored as black in a spectrogram. No matter how negative (as they might just be the FFT's numerical noise, which can be a huge negative dB number or even NaN or -Inf for log(0)).

Related

How to batch the calls in google app script

I was trying to optimize runtime some code that ran really slowly, when searching it up google came up with this: https://developers.google.com/apps-script/guides/support/best-practices#:~:text=Use%20batch%20operations,-Scripts%20commonly%20need&text=Alternating%20read%20and%20write%20commands,data%20out%20with%20one%20command.
it shows an example of inefficient code:
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
xcoord = xmin;
for (var x = 0; x < 100; x++) {
var c = getColorFromCoordinates(xcoord, ycoord);
cell.offset(y, x).setBackgroundColor(c);
xcoord += xincrement;
}
ycoord -= yincrement;
SpreadsheetApp.flush();
}
and efficient code:
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColorFromCoordinates(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
I tried to understand how this code works and tried running it but first of all "cell" doesn't seem to get used and I do not understand the code at all. What is a version of the code that actually works and how does this make it more efficient? And what part of this code batches the calls and how can I use this in my own coding?
Basically, what it does it reduce the number of calls by its methods.
The inefficient code above calls offset and setBackgroundColor every loop thus making it resource intensive and time consuming.
For the efficient code, it uses the loop to build the 2d array which then will be used on a single call on the method setBackgroundColors to execute it by bulk.
What takes much of the run time is the method calls, so reducing it would be very beneficial. This would make use of loops to build 2d arrays for the array versions of the methods single execution.
e.g.:
setValue -> setValues
setBackgroundColor -> setBackgroundColors
Pseudocode:
from:
loop {
setValue(x[i][j])
}
to:
loop {
x[i][j] = data
}
setValues(x)

LED matrix simulation

I never really write much actionscript let alone as3.
I've run into a little problem and would like to ask for ideas or help.
I am trying to simulate a LED matrix of 40x40 LEDs, that are supposed to blink at slightly different intervals including fade out.
I use an array for new sprites and write the 40x40 to screen - applying various tweens in the process. Event listeners are supposed to restart the tweens, so they would loop at the various tween intervals set in the 'for' loop.
task complete: this is what i came up with. it's pretty cost intensive with the number of eventlisteners. cpu temp will increase slightly but it works. still interested in a more efficient way of doing similar animation. pls grant me that i'm not really familiar with as3.
mistake seems to have been the call to tween in the onFinish function. should have been e.target.yoyo() instead of the array element.
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
import flash.display.Sprite;
var stageWidth: Number = stage.stageWidth;
var n: Number = 40; //matrix width and height
var nsquare: Number = (n * n);
var segment: Number = stageWidth / n; //stage diveded by matrix n
var dot_items: Array = [];
var tweens: Array = [];
var basetime: int = 1; //transition base time ..add half basetime random for various transition speed.
for (var l: int = 0; l < n; l++) {
for (var i: int = 0; i < n; i++) {
var count: Number = (l * n) + i;
dot_items[count] = new Sprite();
dot_items[count].graphics.beginFill(0x141496, 1);
dot_items[count].graphics.drawCircle(segment / 2 + (segment * i), segment / 2 + (segment * l), segment / 2);
dot_items[count].graphics.endFill();
addChild(dot_items[count]);
}
}
for (var it: int = 0; it < nsquare; it++) {
var fadeTime: Number = Math.random() * (basetime / 3) + basetime;
tweens[it] = new Tween(dot_items[it], "alpha", Regular.easeInOut, 1, 0, fadeTime, true);
function onFinish(e: TweenEvent): void {
e.target.yoyo();
}
tweens[it].addEventListener(TweenEvent.MOTION_FINISH, onFinish);
}

SVG Raphaeljs Creating a grid of rectangles

I want to create a user defined grid of rectangles using SVG Raphaeljs. The method I am using at the moment is close to what I want it to do but its clearly not right.
My code as of now :
Creating the rectangles and trying to get them placed in an even grid of equal distance from each other
function startup() {
var paper = Raphael(50, 50, 1500, 875);
for (var i = 0; i <= 7; i++) {
for (var j = 0; j <= 4; j++) {
var offset = i; // Stores the number to remove from the next variable to keep an even distance between shapes
var moveRight = (i + 20 - offset) * i; // new variable stores the amount to move the next rectangle along by adding 20 (distance in pixels
// to move to the right) to the loop counter i and then subtracting the offset which is the variable i
// before the + 20 was added and then multiplying it all by i again.
var moveDown = (j + 35 - offset) * j;
var c = paper.rect(moveRight, moveDown, 15, 20);
c.attr("fill", "#f00");
c.attr("stroke", "#fff");
}
}
}
The above currently produces this wonky grid as a result of my poor coding.
I need this to work in such a way that the user can enter the actual amount of rows and columns just by editing the values I put into the for loops and then using that number to change the distance each shape is placed,
As you can see I tried to do this by making a rough formula but I am now stuck, so any help is appreciated.
Ok, silly on my part. I've noticed a mistake and I've amended my code to the following:
function startup() {
var paper = Raphael(50, 50, 1500, 875);
for (var i = 0; i <= 7; i++) {
for (var j = 0; j <= 4; j++) {
var offseti = i; // Stores the number to remove from the next variable to keep an even distance between shapes
var moveRight = (i + 20 - offseti) * i; // new variable stores the amount to move the next rectangle along by adding 20 (distance in pixels
// to move to the right) to the loop counter i and then subtracting the offset which is the variable i
var offsetj = j; // before the + 20 was added and then multiplying it all by i again.
var moveDown = (j + 25 - offsetj) * j;
var c = paper.rect(moveRight, moveDown, 15, 20);
c.attr("fill", "#f00");
c.attr("stroke", "#fff");
}
}
}

Box2D - FRIM (Frame Rate Independent Movement)

I've been trying to implement a FRIM system for my game for the last couple of days.I did some research and came upon this article - it seemed simple enough to implement so I got started.
Everything seems to work fine except I get some temporal aliasing (moving bodies seem to jump ahead a bit) - this happens when more Box2D steps are processed....I think.
private const FIXED_TIMESTEP:Number = 1 / 60;
private const velocityIterations:int = 8;
private const positionIterations:int = 3;
private var fixedTimestepAccumulator:Number = 0;
private var fixedTimestepAccumulatorRatio:Number = 0;
public function Step(dt:Number):void
{
//dt - time between frames - I'm passing the e.passedTime - from the enter frame event; using Starling
fixedTimestepAccumulator += dt;
var nSteps:uint = Math.floor(fixedTimestepAccumulator / FIXED_TIMESTEP);
if (nSteps > 0)
{
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
}
fixedTimestepAccumulatorRatio = fixedTimestepAccumulator / FIXED_TIMESTEP;
var nStepsClamped:int = Math.min(nSteps, MAX_STEPS);
for (var i:int = 0; i < nStepsClamped; ++i)
{
resetSmoothStates();
singleStep(FIXED_TIMESTEP);
}
world.ClearForces();
smoothStates();
}
private function resetSmoothStates():void
{
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
//each of my bodies have a reference to their sprite (actor) in userData
var _userdata:MyUserData=bb.GetUserData();
_userdata.x = _userdata.bodyPreviousX = bb.GetPosition().x * RATIO;
_userdata.y= _userdata.bodyPreviousY = - bb.GetPosition().y* RATIO;
_userdata.rotation = _userdata.bodypreviousRotation= _userdata.bodypreviousRotation = - bb.GetAngle();
}
}
}
private function smoothStates():void
{
var oneMinusRatio:Number = 1.0 - fixedTimestepAccumulatorRatio;
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
var userdata=bb.GetUserData();
userdata.x = (fixedTimestepAccumulatorRatio * bb.GetPosition().x * RATIO + oneMinusRatio * userdata.bodyPreviousX) ;
userdata.y = (- fixedTimestepAccumulatorRatio * bb.GetPosition().y * RATIO + oneMinusRatio * userdata.bodyPreviousY) ;
userdata.rotation = (- fixedTimestepAccumulatorRatio * bb.GetAngle() + oneMinusRatio * userdata.bodypreviousRotation);
}
}
}
private function singleStep(dt:Number):void
{
Input();
world.Step(dt, velocityIterations, positionIterations);
}
What am I doing wrong?
Any help, suggestions would be highly appreciated.
Thanks
I did this once in a game I was working on so that I could lockstep the game to a certain update rate (this was in iOS). This was based on the code in Daley's book (Learning iOS Game Programming), which was based on some other article in the web (I believe, it may be Allen Bishop's). The code looked like this:
void GameManager::UpdateGame()
{
const uint32 MAXIMUM_FRAME_RATE = Constants::DEFAULT_OBJECT_CYCLES_PER_SECOND();
const uint32 MINIMUM_FRAME_RATE = 10;
const uint32 MAXIMUM_CYCLES_PER_FRAME = (MAXIMUM_FRAME_RATE/MINIMUM_FRAME_RATE);
const double UPDATE_INTERVAL = (1.0/MAXIMUM_FRAME_RATE);
static double lastFrameTime = 0.0;
static double cyclesLeftOver = 0.0;
double currentTime;
double updateIterations;
currentTime = CACurrentMediaTime();
updateIterations = ((currentTime - lastFrameTime) + cyclesLeftOver);
if(updateIterations > (MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL))
{
updateIterations = MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL;
}
while (updateIterations >= UPDATE_INTERVAL)
{
// DebugLogCPP("Frame Running");
updateIterations -= UPDATE_INTERVAL;
// Set the random seed for this cycle.
RanNumGen::SetSeed(_cycleManager->GetObjectCycle());
// Dispatch messages.
_messageManager->SendMessages();
// Update all entities.
_entityManager->Update();
// Update the physics
_gameWorldManager->Update(Constants::DEFAULT_OBJECT_CYCLE_SECONDS());
// Advance the cycle clock.
_cycleManager->Update();
}
cyclesLeftOver = updateIterations;
lastFrameTime = currentTime;
}
I can't put my finger on the specific item that is wrong in yours. However, this part is suspicious:
var nStepsClamped:int = Math.min(nSteps, MAX_STEPS);
Before this, you updated your accumulator with:
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
But now the actual number of steps you are going to execute may be different because of the clamping (nStepsClamped). So your time accumulation is different than the number of steps you actually execute.
Was this helpful?
I decided to go with another approach. I'm using filtered delta times for the physics (I know this can cause some problems).
Here's what I'm doing now:
//Play around with this filter value if things don't look right
var filter:Number=0.4;
filtered_dt= time_between_frames * filter + filtered_dt * (1 - filter);
//Poll imputs and apply forces
// I use velocityIterations =6, positionIterations=3
world.Step(filtered_dt, velocityIterations, positionIterations);
//move sprites here
world.ClearForces();
Another thing you have to do is to scale the forces you apply to your bodies using filtered_dt so things don't "explode" when the frame rate changes a lot.
Hope this helps some one else ... it's not the perfect solution but it works for me.
If you have slow moving bodies the interpolation method above should work fine too.

An alternative to bitmapdata with less memory usage?

Im using a very big BitmapData as a pathing map for my platformer game, however I only use pixels for 4 particular values, instead of, well 4294967295.
Would converting this Bitmapdata as 2 2D Vectors of Boolean save me some memory ?
And if it does, what about performance, would it be faster or slower to do something like:
MapGetPixel(x:int, y:int):int
{
return MapBoolFirst[x][y] + MapBoolSecond[x][y]*2;
}
instead of the bitmapdata class getPixel32(x:int, y:int):uint ?
In short im looking for a way to reduce the size and/or optimize my 4 colors bitmapdata.
Edit :
Using my boolean method apparently consumes 2 times more memory than the bitmapdata one.
I guess a boolean takes more than one bit in memory, else that would be too easy. So im thinking about bitshifting ints and thus have an int store the value for several pixels, but im not sure about this…
Edit 2 :
Using int bitshifts I can manage the data of 16 pixels into a single int, this trick should work to save some memory, even if it'll probably hit performance a bit.
Bitshifting will be the most memory-optimized way of handling it. Performance wise, that shouldn't be too big of an issue unless you need to poll a lot of asks each frame. The issue with AS is that booleans are 4bits :(
As I see it you can handle it in different cases:
1) Create a lower res texture for the hit detections, usually it is okay to shrink it 4 times (256x256 --> 64x64)
2) Use some kind of technique of saving that data into some kind of storage (bool is easiest, but if that is too big, then you need to find another solution for it)
3) Do the integer-solution (I haven't worked with bit-shifting before, so I thought it would be a fun challenge, here's the result of that)
And that solution is way smaller than the one used for boolean, and also way harder to understand :/
public class Foobar extends MovieClip {
const MAX_X:int = 32;
const MAX_Y:int = 16;
var _itemPixels:Vector.<int> = new Vector.<int>(Math.ceil(MAX_X * MAX_Y / 32));
public function Foobar() {
var pre:Number = System.totalMemory;
init();
trace("size=" + _itemPixels.length);
for (var i = 0; i < MAX_Y; ++i) {
for (var j = 0; j < MAX_X; ++j) {
trace("item=" + (i*MAX_X+j) + "=" + isWalkablePixel(j, i));
}
}
trace("memory preInit=" + pre);
trace("memory postInit=" + System.totalMemory);
}
public function init() {
var MAX_SIZE:int = MAX_X * MAX_Y;
var id:int = 0;
var val:int = 0;
var b:Number = 0;
for(var y=0; y < MAX_Y; ++y) {
for (var x = 0; x < MAX_X; ++x) {
b = Math.round(Math.random()); //lookup the pixel from some kind of texture or however you expose the items
if (b == 1) {
id = Math.floor((y * MAX_X + x) / 32);
val = _itemPixels[id];
var it:uint = (y * MAX_X + x) % 32;
b = b << it;
val |= b;
_itemPixels[id] = val;
}
}
}
}
public function isWalkablePixel(x, y):Boolean {
var val:int = _itemPixels[Math.floor((y * MAX_X + x) / 32)];
var it:uint = 1 << (y * MAX_X + x) % 32;
return (val & it) != 0;
}
}
One simple improvement is to use a ByteArray instead of BitmapData. That means each "pixel" only takes up 1 byte instead of 4. This is still a bit wasteful since you're only needing 2 bits per pixel and not 8, but it's a lot less than using BitmapData. It also gives you some "room to grow" without having to change anything significant later if you need to store more than 4 values per pixel.
ByteArray.readByte()/ByteArray.writeByte() works with integers, so it's really convenient to use. Of course, only the low 8 bits of the integer is written when calling writeByte().
You set ByteArray.position to the point (0-based index) where you want the next read or write to start from.
To sum up: Think of the ByteArray as a one dimensional Array of integers valued 0-255.
Here are the results, I was using an imported 8 bit colored .png by the way, not sure if it changes anything when he gets converted into a
BitmapData.
Memory usage :
BitmapData : 100%
Double Boolean vectors : 200%
Int Bitshifting : 12%
So int bitshifting win hands down, it works pretty much the same way as hexadecimal color components, however in that case I store 16 components (pixel values in 2 bits) not the 4 ARGB:
var pixels:int = -1;// in binary full of 1
for (var i:int = 0; i < 16; i++)
trace("pixel " + (i + 1) +" value : " + (pixels >> i * 2 & 3));
outputs as expected :
"pixel i value : 3"