dev@74
|
1 import {
|
dev@236
|
2 Component,
|
dev@236
|
3 OnInit,
|
dev@236
|
4 Output,
|
dev@236
|
5 EventEmitter,
|
dev@236
|
6 Input,
|
dev@74
|
7 OnDestroy
|
dev@74
|
8 } from '@angular/core';
|
dev@236
|
9 import {
|
dev@236
|
10 FeatureExtractionService
|
dev@236
|
11 } from '../services/feature-extraction/feature-extraction.service';
|
dev@236
|
12 import {ListResponse} from 'piper';
|
dev@236
|
13 import {Subscription} from 'rxjs/Subscription';
|
dev@440
|
14 import {HigherLevelFeatureShape} from "../visualisations/FeatureUtilities";
|
dev@44
|
15
|
dev@47
|
16 export interface ExtractorOutputInfo {
|
dev@47
|
17 extractorKey: string;
|
dev@47
|
18 combinedKey: string;
|
dev@47
|
19 outputId: string;
|
dev@44
|
20 name: string;
|
dev@440
|
21 iconName?: string;
|
dev@44
|
22 }
|
dev@44
|
23
|
dev@423
|
24 interface ExtractorInfo {
|
dev@423
|
25 name: string;
|
dev@423
|
26 outputs: ExtractorOutputInfo[];
|
dev@423
|
27 }
|
dev@423
|
28
|
dev@440
|
29 const crudeTypeUriMap: {[key: string]: HigherLevelFeatureShape} = {
|
dev@440
|
30 'http://purl.org/ontology/af/Beat': 'instants',
|
dev@440
|
31 'http://purl.org/ontology/af/Chromagram': 'matrix',
|
dev@440
|
32 'http://purl.org/ontology/af/Spectrogram': 'matrix',
|
dev@440
|
33 'http://purl.org/ontology/af/KeyChange': 'instants',
|
dev@440
|
34 'http://purl.org/ontology/af/OnsetDetectionFunction': 'vector',
|
dev@440
|
35 'http://purl.org/ontology/af/Onset': 'instants',
|
dev@440
|
36 'http://purl.org/ontology/af/StructuralSegment': 'instants',
|
dev@440
|
37 'http://purl.org/ontology/af/TonalOnset': 'instants',
|
dev@440
|
38 'http://purl.org/ontology/af/Note': 'notes',
|
dev@440
|
39 'http://purl.org/ontology/af/ChordSegment': 'instants',
|
dev@440
|
40 'http://purl.org/ontology/af/MusicSegment': 'instants',
|
dev@440
|
41 'http://purl.org/ontology/af/Pitch': 'tracks'
|
dev@440
|
42 };
|
dev@440
|
43
|
dev@440
|
44 const featureIconMap = {
|
dev@440
|
45 vector: 'show_chart',
|
dev@440
|
46 matrix: 'grid_on',
|
dev@440
|
47 tracks: 'multiline_chart',
|
dev@440
|
48 instants: 'view_week',
|
dev@440
|
49 notes: 'audiotrack',
|
dev@440
|
50 };
|
dev@440
|
51
|
dev@44
|
52 @Component({
|
dev@236
|
53 selector: 'ugly-feature-extraction-menu',
|
dev@44
|
54 templateUrl: './feature-extraction-menu.component.html',
|
dev@44
|
55 styleUrls: ['./feature-extraction-menu.component.css']
|
dev@44
|
56 })
|
dev@74
|
57 export class FeatureExtractionMenuComponent implements OnInit, OnDestroy {
|
dev@44
|
58
|
dev@48
|
59 @Input()
|
dev@48
|
60 set disabled(isDisabled: boolean) {
|
dev@48
|
61 this.isDisabled = isDisabled;
|
dev@48
|
62 }
|
dev@48
|
63
|
dev@48
|
64 get disabled() {
|
dev@48
|
65 return this.isDisabled;
|
dev@48
|
66 }
|
dev@426
|
67 @Input() onRequestOutput: () => void;
|
dev@48
|
68
|
dev@47
|
69 @Output() requestOutput: EventEmitter<ExtractorOutputInfo>;
|
dev@47
|
70
|
dev@48
|
71 private isDisabled: boolean;
|
dev@74
|
72 private populateExtractors: (available: ListResponse) => void;
|
dev@423
|
73 extractors: Iterable<ExtractorInfo>;
|
dev@74
|
74 private librariesUpdatedSubscription: Subscription;
|
dev@433
|
75 private isLoading: boolean;
|
dev@44
|
76
|
dev@44
|
77 constructor(private piperService: FeatureExtractionService) {
|
dev@44
|
78 this.extractors = [];
|
dev@51
|
79 this.requestOutput = new EventEmitter<ExtractorOutputInfo>();
|
dev@48
|
80 this.isDisabled = true;
|
dev@74
|
81 this.populateExtractors = available => {
|
dev@423
|
82 this.extractors = available.available.reduce((acc, staticData) => {
|
dev@423
|
83 const name = staticData.basic.name;
|
dev@423
|
84 const outputs: ExtractorOutputInfo[] =
|
dev@423
|
85 staticData.basicOutputInfo.map(output => {
|
dev@423
|
86 const combinedKey = `${staticData.key}:${output.identifier}`;
|
dev@440
|
87 const hasTypeInfo = staticData.staticOutputInfo &&
|
dev@440
|
88 staticData.staticOutputInfo.get(output.identifier) &&
|
dev@440
|
89 staticData.staticOutputInfo.get(output.identifier).typeURI;
|
dev@440
|
90 const getIcon = () => featureIconMap[crudeTypeUriMap[
|
dev@440
|
91 staticData.staticOutputInfo.get(output.identifier).typeURI
|
dev@440
|
92 ]];
|
dev@440
|
93 const hasIcon = hasTypeInfo && getIcon();
|
dev@440
|
94 return Object.assign({
|
dev@440
|
95 extractorKey: staticData.key,
|
dev@440
|
96 combinedKey: combinedKey,
|
dev@440
|
97 name: output.name,
|
dev@440
|
98 outputId: output.identifier
|
dev@440
|
99 },
|
dev@440
|
100 hasIcon ? {iconName: getIcon()} : {}
|
dev@440
|
101 );
|
dev@46
|
102 });
|
dev@423
|
103 acc.push({name, outputs});
|
dev@423
|
104 return acc;
|
dev@423
|
105 }, [] as ExtractorInfo[]);
|
dev@433
|
106 this.isLoading = false;
|
dev@74
|
107 };
|
dev@74
|
108 }
|
dev@74
|
109
|
dev@74
|
110 ngOnInit() {
|
dev@236
|
111 this.librariesUpdatedSubscription =
|
dev@236
|
112 this.piperService.librariesUpdated$.subscribe(this.populateExtractors);
|
dev@324
|
113 this.piperService.list().then(this.populateExtractors);
|
dev@44
|
114 }
|
dev@44
|
115
|
dev@423
|
116 extract(info: ExtractorOutputInfo): void {
|
dev@426
|
117 if (this.onRequestOutput) {
|
dev@426
|
118 this.onRequestOutput();
|
dev@426
|
119 }
|
dev@431
|
120 if (info && !this.disabled) {
|
dev@100
|
121 this.requestOutput.emit(info);
|
dev@100
|
122 }
|
dev@47
|
123 }
|
dev@47
|
124
|
dev@238
|
125 load(): void {
|
dev@433
|
126 this.isLoading = true;
|
dev@324
|
127 this.piperService.updateAvailableLibraries();
|
dev@74
|
128 }
|
dev@74
|
129
|
dev@74
|
130 ngOnDestroy(): void {
|
dev@74
|
131 this.librariesUpdatedSubscription.unsubscribe();
|
dev@74
|
132 }
|
dev@44
|
133 }
|