annotate src/app/visualisations/notes/notes.component.ts @ 380:b81ed55fdee3

Basic notes component in place. Room for reducing dupe across these WaveComponent derived components, but will wait until all of them are implemented to see the common logic.
author Lucas Thompson <dev@lucas.im>
date Wed, 31 May 2017 15:15:55 +0100
parents
children 1241ca979fd9
rev   line source
dev@380 1 /**
dev@380 2 * Created by lucast on 31/05/2017.
dev@380 3 */
dev@380 4 import {WavesComponent} from '../waves-base.component';
dev@380 5 import {
dev@380 6 AfterViewInit,
dev@380 7 ChangeDetectionStrategy,
dev@380 8 Component,
dev@380 9 ElementRef,
dev@380 10 Input,
dev@380 11 ViewChild
dev@380 12 } from '@angular/core';
dev@380 13 import {Note} from '../FeatureUtilities';
dev@380 14 import Waves from 'waves-ui-piper';
dev@380 15
dev@380 16 @Component({
dev@380 17 selector: 'ugly-notes',
dev@380 18 templateUrl: '../waves-template.html',
dev@380 19 styleUrls: ['../waves-template.css'],
dev@380 20 changeDetection: ChangeDetectionStrategy.OnPush
dev@380 21 })
dev@380 22 export class NotesComponent extends WavesComponent implements AfterViewInit {
dev@380 23
dev@380 24 @ViewChild('track') trackDiv: ElementRef;
dev@380 25
dev@380 26 private mFeature: Note[];
dev@380 27 private height: number; // As it stands, height is fixed. Store once onInit.
dev@380 28
dev@380 29 @Input() set notes(notes: Note[]) {
dev@380 30 this.mFeature = notes;
dev@380 31 this.update();
dev@380 32 }
dev@380 33
dev@380 34 get notes(): Note[] {
dev@380 35 return this.mFeature;
dev@380 36 }
dev@380 37
dev@380 38 ngAfterViewInit(): void {
dev@380 39 this.height = this.trackDiv.nativeElement.getBoundingClientRect().height;
dev@380 40 this.renderTimeline(this.trackDiv);
dev@380 41 this.update();
dev@380 42 }
dev@380 43
dev@380 44 update(): void {
dev@380 45 if (!this.waveTrack || !this.notes) { return; }
dev@380 46 this.clearTimeline(this.trackDiv);
dev@380 47
dev@380 48 this.addLayer(
dev@380 49 new Waves.helpers.PianoRollLayer(
dev@380 50 this.notes,
dev@380 51 {
dev@380 52 height: this.height,
dev@380 53 color: this.colour,
dev@380 54 yDomain: findVerticalRange(this.notes)
dev@380 55 }
dev@380 56 ),
dev@380 57 this.waveTrack,
dev@380 58 this.timeline.timeContext
dev@380 59 );
dev@380 60 }
dev@380 61 }
dev@380 62
dev@380 63 // TODO there might be scope to create a generic utility function like this
dev@380 64 function findVerticalRange(notes: Note[]): [number, number] {
dev@380 65 let [min, max] = notes.reduce((acc, note) => {
dev@380 66 const [min, max] = acc;
dev@380 67 return [Math.min (min, note.pitch), Math.max (max, note.pitch)];
dev@380 68 }, [Infinity, -Infinity]);
dev@380 69 if (min === Infinity || min < 0 || max < 0) {
dev@380 70 min = 0;
dev@380 71 max = 127;
dev@380 72 }
dev@380 73 // round min and max to octave boundaries (starting at C as in MIDI)
dev@380 74 return [
dev@380 75 12 * Math.floor(min / 12),
dev@380 76 12 * Math.ceil(max / 12)
dev@380 77 ];
dev@380 78 }