Ver Fonte

FFT class

Andrea Condoluci há 9 anos atrás
pai
commit
551ec0d0bd

+ 4 - 1
Gruntfile.js

@@ -37,7 +37,10 @@ module.exports = function (grunt) {
                 }
             },
             options: {
-                plugin: ['tsify']
+                plugin: ['tsify'],
+                browserifyOptions: {
+                  standalone: 'MeasureSizeCalculator'
+                }
             }
         },
         // Uglify

+ 3 - 1
package.json

@@ -53,6 +53,8 @@
         "karma-mocha-reporter": "",
         "karma-phantomjs-launcher": "",
 
-        "vexflow": ""
+        "vexflow": "",
+
+        "fft": "0.2.*"
     }
 }

+ 11 - 9
src/MusicalScore/Calculation/MeasureSizeCalculator.ts

@@ -109,7 +109,7 @@ export class MeasureSizeCalculator {
     );
     for (let clef of clefs) {
       voicesBoundingBox = voicesBoundingBox.mergeWith(
-        this.getClefBoundingBox(clef)
+        MeasureSizeCalculator.getClefBoundingBox(clef)
       );
     }
 
@@ -123,30 +123,32 @@ export class MeasureSizeCalculator {
     );
   }
 
-  private getClefBoundingBox(clef: Vex.Flow.Clef): Vex.Flow.BoundingBox {
+  public static getClefBoundingBox(clef: Vex.Flow.Clef): Vex.Flow.BoundingBox {
+    let clef2: any = clef;
+    clef2.placeGlyphOnLine(clef2.glyph, clef2.stave, clef2.clef.line);
     let glyph: any = clef.glyph;
     let x_pos: number = clef.x + glyph.x_shift;
     let y_pos: number = clef.stave.getYForGlyphs() + glyph.y_shift;
     let scale: number = glyph.scale;
     let outline: any[] = glyph.metrics.outline;
-    let xmin: number = 0, xmax: number = 0,
-      ymin: number = 0, ymax: number = 0;
+    let xmin: number = 0, xmax: number = 0, ymin: number = 0, ymax: number = 0;
 
     function update(i: number): void {
-      let x: number = outline[i];
-      let y: number = outline[i];
+      let x: number = outline[i + 1];
+      let y: number = outline[i + 2];
       xmin = Math.min(xmin, x);
       xmax = Math.max(xmax, x);
       ymin = Math.min(ymin, y);
       ymax = Math.max(ymax, y);
     }
 
-    for (let i of outline) {
+    for (let i = 0, len = outline.length; i < len; i += 3) {
+      console.log(i, outline[i]);
       switch (<string> outline[i]) {
         case "m": update(i); break;
         case "l": update(i); break;
-        case "q": i++; update(i); break;
-        case "b": i++; i++; update(i); break;
+        case "q": i += 2; update(i); break;
+        case "b": i += 4; update(i); break;
         default: break;
       }
 

+ 56 - 0
src/Util/fft.ts

@@ -0,0 +1,56 @@
+module FFT {
+
+  // typing for the FFT npm package
+  export declare class complex {
+    constructor(n: number, inverse: boolean);
+    public simple(output: Float64Array, input: Float64Array, type: string): void;
+  }
+
+  export function toRealImag(timeData: Float64Array): any {
+    let n: number = timeData.length;
+    let fft: any = new FFT.complex(n << 1, false);
+    let output: Float64Array = new Float64Array(n << 1);
+    let input: Float64Array = new Float64Array(n << 1);
+    // copy timeData into the input array
+    // FIXME: is this fix needed?
+    // problem: complex transform, real timeData
+    for (let i = 0; i < n; i++) {
+      input[i << 1] = timeData[i];
+      input[i << 1 + 1] = 0;
+    }
+    fft.simple(output, input, "complex");
+    // Split output in real/imaginary parts
+    let real: Float64Array = new Float64Array(n);
+    let imag: Float64Array = new Float64Array(n);
+    for (let i: number = 0; i < n; i ++) {
+      real[i] = output[i << 1];
+      imag[i] = output[i << 1 + 1];
+    }
+    return { real: real, imag: imag };
+  }
+
+  export function toAmplPhas(timeData: Float64Array): any {
+    let n: number = timeData.length;
+    let fft: any = new FFT.complex(n << 1, false);
+    let output: Float64Array = new Float64Array(n << 1);
+    let input: Float64Array = new Float64Array(n << 1);
+    // copy timeData into the input array
+    // FIXME: is this fix needed?
+    // problem: complex transform, real timeData
+    for (let i = 0; i < n; i++) {
+      input[i << 1] = timeData[i];
+      input[i << 1 + 1] = 0;
+    }
+    fft.simple(output, input, "complex");
+    // Represent complex output in amplitude/phase form
+    let ampl: Float64Array = new Float64Array(n);
+    let phas: Float64Array = new Float64Array(n);
+    for (let i = 0, x: number, y: number; i < n; i += 1) {
+      x = output[i << 1];
+      y = output[i << 1 + 1];
+      ampl[i] = Math.sqrt(x * x + y * y);
+      phas[i] = Math.atan2(y, x);
+    }
+    return { amplitude: ampl, phase: phas };
+  }
+}

+ 38 - 0
test/MusicalScore/Calculation/MeasureSizeCalculator.ts

@@ -47,4 +47,42 @@ describe("Measure Size Calculator Tests", () => {
     chai.expect(calc.getTopBorder()).to.equal(0);
     done();
   });
+
+  it("Will certainly pass", (done: MochaDone) => {
+    let visual = function(func: (r: any, ctx: any) => void) {
+      let canvas: HTMLCanvasElement = document.createElement("canvas");
+      document.body.appendChild(canvas);
+      let renderer: any = new Vex.Flow.Renderer(
+        canvas,
+        Vex.Flow.Renderer.Backends.CANVAS
+      );
+      renderer.resize(300, 100);
+      let ctx: any = renderer.getContext();
+      ctx.setFont("Arial", 10, "").setBackgroundFillStyle("#eed");
+      func(renderer, ctx);
+    }
+
+    visual(function(renderer, ctx) {
+      renderer.resize(420, 120);
+      let stave: Vex.Flow.Stave = new Vex.Flow.Stave(10, 0, 410);
+      stave.setContext(ctx);
+      for (var t in Vex.Flow.Clef.types) {
+        let clef: Vex.Flow.Clef = new Vex.Flow.Clef(t);
+        stave.addModifier(clef, Vex.Flow.StaveModifier.Position.BEGIN);
+        stave.format();
+        // (*&^%$#@) //
+        // FIXME HERE? NaN FIXME FIXME FIXME //
+        clef.setStave(stave);
+        let bb: Vex.Flow.BoundingBox =
+          MeasureSizeCalculator.getClefBoundingBox(clef);
+        console.log(bb);
+        ctx.rect(bb.getX(), bb.getY(), bb.getW(), bb.getH());
+        ctx.stroke();
+      }
+      stave.draw();
+    });
+
+    done();
+  });
+
 });

+ 14 - 0
typings/vexflow.d.ts

@@ -44,6 +44,9 @@ declare namespace Vex {
       getNumLines(): number;
       getLineForY(y: number): number;
       getModifiers(pos: any, cat: any): Vex.Flow.Clef[]; // FIXME
+      setContext(ctx: any);
+      addModifier(mod: any, pos: any);
+      draw(): void;
 
       constructor(x: number, y: number, width: number);
     }
@@ -54,14 +57,25 @@ declare namespace Vex {
 
     export class Clef {
       public static category: string;
+      public static types: { [type: string]: any; } ;
       public glyph: any;
       public x: number;
       public stave: Stave;
 
       public getBoundingBox(): Vex.Flow.BoundingBox;
+      public setStave(stave: Vex.Flow.Stave): void;
+      constructor(type: any);
+    }
 
+    export class Renderer {
+      constructor(canvas: HTMLCanvasElement, backend: any);
+      public resize(a: number, b:number);
+      public getContext(): any;
+      public static Backends: any;
     }
 
+    //export class
+
   }
 }