Przeglądaj źródła

Merge with master

Andrea Condoluci 9 lat temu
rodzic
commit
b10e418b49

+ 4 - 1
Gruntfile.js

@@ -38,7 +38,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.*"
     }
 }

+ 53 - 1
src/MusicalScore/Calculation/MeasureSizeCalculator.ts

@@ -99,8 +99,20 @@ export class MeasureSizeCalculator {
     //console.log("this.width", this.voicesWidth);
     //console.log("voicesBB", voicesBoundingBox.getW());
 
-    // FIXME the following: should consider stave modifiers
+
     //this.height = voicesBoundingBox.getH(); FIXME
+
+    // Consider clefs
+    let clefs: Vex.Flow.Clef[] = stave.getModifiers(
+      Vex.Flow.StaveModifier.Position.LEFT,
+      Vex.Flow.Clef.category
+    );
+    for (let clef of clefs) {
+      voicesBoundingBox = voicesBoundingBox.mergeWith(
+        MeasureSizeCalculator.getClefBoundingBox(clef)
+      );
+    }
+
     this.topBorder = Math.min(
       0,
       Math.floor(stave.getLineForY(voicesBoundingBox.getY()))
@@ -110,4 +122,44 @@ export class MeasureSizeCalculator {
       Math.ceil(stave.getLineForY(voicesBoundingBox.getY() + voicesBoundingBox.getH()))
     );
   }
+
+  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;
+
+    function update(i: number): void {
+      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 = 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 += 2; update(i); break;
+        case "b": i += 4; update(i); break;
+        default: break;
+      }
+
+    }
+    return new Vex.Flow.BoundingBox(
+      x_pos + xmin * scale,
+      y_pos - ymin * scale,
+      (xmax - xmin) * scale,
+      (ymin - ymax) * scale
+    );
+  }
+
+
 }

+ 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();
+  });
+
 });

+ 34 - 2
typings/vexflow.d.ts

@@ -1,4 +1,4 @@
-declare namespace VexFlow {
+declare namespace Vex {
   export module Flow {
 
     export class Formatter {
@@ -15,6 +15,8 @@ declare namespace VexFlow {
       getY(): number;
       getW(): number;
       getH(): number;
+
+      constructor(x: number, y: number, w: number, h: number);
     }
 
     export class Voice {
@@ -33,6 +35,7 @@ declare namespace VexFlow {
       start_x: number;
       end_x: number;
 
+      getYForGlyphs(): number;
       getWidth(): number;
       setWidth(width: number): Stave;
       getNoteStartX(): number;
@@ -40,13 +43,42 @@ declare namespace VexFlow {
       getSpacingBetweenLines(): number;
       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);
     }
 
+    export class StaveModifier {
+      public static Position: any;
+    }
+
+    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
+
   }
 }
 
 declare module "vexflow" {
-    export = VexFlow;
+    export = Vex;
 }