changeset 47:933c64ebcd13

Some extraction logic in place.
author Lucas Thompson <dev@lucas.im>
date Mon, 05 Dec 2016 16:57:34 +0000
parents 88052122ec01
children af0b4b05311c
files src/app/app.component.html src/app/app.component.ts src/app/feature-extraction-menu/feature-extraction-menu.component.html src/app/feature-extraction-menu/feature-extraction-menu.component.ts src/app/playback-control/playback-control.component.ts src/app/services/feature-extraction/FeatureExtractionWorker.ts src/app/services/feature-extraction/feature-extraction.service.ts
diffstat 7 files changed, 92 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/src/app/app.component.html	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/app.component.html	Mon Dec 05 16:57:34 2016 +0000
@@ -22,7 +22,7 @@
         <app-playback-control class="playback-content"></app-playback-control>
       </md-tab>
       <md-tab label="Feature Extraction">
-        <app-feature-extraction-menu></app-feature-extraction-menu>
+        <app-feature-extraction-menu (requestOutput)="extractFeatures($event)"></app-feature-extraction-menu>
       </md-tab>
     </md-tab-group>
   </md-sidenav>
--- a/src/app/app.component.ts	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/app.component.ts	Mon Dec 05 16:57:34 2016 +0000
@@ -1,5 +1,7 @@
 import {Component} from '@angular/core';
 import {AudioPlayerService} from "./services/audio-player/audio-player.service";
+import {FeatureExtractionService} from "./services/feature-extraction/feature-extraction.service";
+import {ExtractorOutputInfo} from "./feature-extraction-menu/feature-extraction-menu.component";
 
 @Component({
   selector: 'app-root',
@@ -9,7 +11,8 @@
 export class AppComponent {
   audioBuffer: AudioBuffer; // TODO consider revising
 
-  constructor(private audioService: AudioPlayerService) {}
+  constructor(private audioService: AudioPlayerService,
+              private piperService: FeatureExtractionService) {}
 
   onFileOpened(file: File) {
     const reader: FileReader = new FileReader();
@@ -25,4 +28,17 @@
     };
     reader.readAsArrayBuffer(file);
   }
+
+  extractFeatures(outputInfo: ExtractorOutputInfo) {
+    this.piperService.process({
+      audioData: [...Array(this.audioBuffer.numberOfChannels).keys()]
+        .map(i => this.audioBuffer.getChannelData(i)),
+      audioFormat: {
+        sampleRate: this.audioBuffer.sampleRate,
+        channelCount: this.audioBuffer.numberOfChannels
+      },
+      key: outputInfo.extractorKey,
+      outputId: outputInfo.outputId
+    }).then(data => console.log(data)).catch(err => console.error(err));
+  }
 }
--- a/src/app/feature-extraction-menu/feature-extraction-menu.component.html	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.html	Mon Dec 05 16:57:34 2016 +0000
@@ -1,9 +1,11 @@
-<select id="extractor-outputs">
+<select id="extractor-outputs" #extractorOutputs>
   <option selected></option>
-  <option *ngFor="let extractor of extractors" value="{{extractor.key}}">
+  <option *ngFor="let extractor of extractors" value="{{extractor.combinedKey}}">
     {{extractor.name}}
   </option>
 </select>
 <p>
-  <button md-raised-button color="primary">Extract</button>
+  <button md-raised-button
+          color="primary"
+          (click)="extract(extractorOutputs.value)">Extract</button>
 </p>
--- a/src/app/feature-extraction-menu/feature-extraction-menu.component.ts	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.ts	Mon Dec 05 16:57:34 2016 +0000
@@ -1,8 +1,10 @@
-import {Component, OnInit} from '@angular/core';
+import {Component, OnInit, Output, EventEmitter} from '@angular/core';
 import {FeatureExtractionService} from "../services/feature-extraction/feature-extraction.service";
 
-interface ExtractorInfo {
-  key: string;
+export interface ExtractorOutputInfo {
+  extractorKey: string;
+  combinedKey: string;
+  outputId: string;
   name: string;
 }
 
@@ -13,29 +15,42 @@
 })
 export class FeatureExtractionMenuComponent implements OnInit {
 
-  extractors: ExtractorInfo[];
+  @Output() requestOutput: EventEmitter<ExtractorOutputInfo>;
+
+  private extractorsMap: Map<string, ExtractorOutputInfo>;
+  extractors: Iterable<ExtractorOutputInfo>;
 
   constructor(private piperService: FeatureExtractionService) {
+    this.extractorsMap = new Map();
     this.extractors = [];
+    this.requestOutput = new EventEmitter();
   }
 
   ngOnInit() {
     this.piperService.list().then(available => {
       const maxCharacterLimit = 50;
       available.available.forEach(staticData => {
-        if (staticData.basicOutputInfo.length > 1)
-          staticData.basicOutputInfo.forEach(output => this.extractors.push({
-              key: `${staticData.key}:${output.identifier}`,
-              name: `${staticData.basic.name}: ${output.name}`.substr(0, maxCharacterLimit) + '...'
-            })
-          );
-        else
-          this.extractors.push({
-            key: staticData.key,
-            name: staticData.basic.name.substr(0, maxCharacterLimit) + '...'
+        const isSingleOutputExtractor = staticData.basicOutputInfo.length === 1;
+        staticData.basicOutputInfo.forEach(output => {
+          const combinedKey = `${staticData.key}:${output.identifier}`;
+          this.extractorsMap.set(combinedKey, {
+            extractorKey: staticData.key,
+            combinedKey: combinedKey,
+            name: (
+              isSingleOutputExtractor
+                ? staticData.basic.name
+                : `${staticData.basic.name}: ${output.name}`
+            ).substr(0, maxCharacterLimit) + '...',
+            outputId: output.identifier
           });
+        });
       });
+      this.extractors = [...this.extractorsMap.values()];
     });
   }
 
+  extract(combinedKey: string): void {
+    this.requestOutput.emit(this.extractorsMap.get(combinedKey));
+  }
+
 }
--- a/src/app/playback-control/playback-control.component.ts	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/playback-control/playback-control.component.ts	Mon Dec 05 16:57:34 2016 +0000
@@ -13,9 +13,7 @@
               private featureExtractionService: FeatureExtractionService) {
   }
 
-  ngOnInit() {
-    this.featureExtractionService.testMessageStream();
-  }
+  ngOnInit() {}
 
   emitPlayPause() {
     this.audioService.togglePlaying();
--- a/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Mon Dec 05 16:57:34 2016 +0000
@@ -23,16 +23,20 @@
 
   constructor(workerScope: WorkerGlobalScope) {
     this.workerScope = workerScope;
-    let counter = 0;
-    setInterval(() => this.workerScope.postMessage(counter++), 1000);
     this.piperClient = new PiperSimpleClient(new EmscriptenProxy(VampExamplePlugins()));
     this.workerScope.onmessage = (ev: MessageEvent) => {
+      const sendResponse = (result) => this.workerScope.postMessage({
+        method: ev.data.method,
+        result: result
+      });
       switch (ev.data.method) {
         case 'list':
-          this.piperClient.list({}).then(this.workerScope.postMessage);
+          this.piperClient.list({}).then(sendResponse);
+          break;
+        case 'process':
+          this.piperClient.process(ev.data.params).then(sendResponse);
       }
     };
   }
 
-
 }
--- a/src/app/services/feature-extraction/feature-extraction.service.ts	Mon Dec 05 11:59:22 2016 +0000
+++ b/src/app/services/feature-extraction/feature-extraction.service.ts	Mon Dec 05 16:57:34 2016 +0000
@@ -1,6 +1,20 @@
-import { Injectable } from '@angular/core';
-import {ListResponse} from "piper";
+import {Injectable} from '@angular/core';
+import {
+  ListResponse, ProcessResponse, ProcessRequest,
+  ListRequest
+} from "piper";
+import {SimpleRequest} from "piper/HigherLevelUtilities";
+import {FeatureList} from "piper/Feature";
 
+interface RequestMessage<RequestType> {
+  method: string;
+  params: RequestType;
+}
+
+interface ResponseMessage<ResponseType> {
+  method: string;
+  result: ResponseType;
+}
 
 @Injectable()
 export class FeatureExtractionService {
@@ -12,24 +26,31 @@
     this.worker = new Worker('bootstrap-feature-extraction-worker.js');
   }
 
-  testMessageStream() {
-    this.worker.addEventListener('message', ev => console.log(ev.data));
-    this.worker.postMessage('anything');
+  list(): Promise<ListResponse> {
+    return this.request<ListRequest, ListResponse>(
+      {method: 'list', params: {}},
+      (ev: MessageEvent) => ev.data.result.available !== undefined
+    ).then(msg => msg.result);
   }
 
-  list(): Promise<ListResponse> {
-    return this.request({method: 'list'}, (ev: MessageEvent) => ev.data.available !== undefined);
+  process(request: SimpleRequest): Promise<FeatureList> {
+    return this.request<SimpleRequest, FeatureList>(
+      {method: 'process', params: request},
+      (ev: MessageEvent) => ev.data.method === 'process'
+    );
   }
 
-  private request<Req, Res>(request: Req, predicate: (ev: MessageEvent) => boolean): Promise<Res> {
+  private request<Req, Res>(request: RequestMessage<Req>,
+                            predicate: (ev: MessageEvent) => boolean)
+  : Promise<ResponseMessage<Res>> {
     return new Promise(res => {
-      const listener = (ev: MessageEvent ) => {
+      const listener = (ev: MessageEvent) => {
         this.worker.removeEventListener('message', listener);
         if (predicate(ev))
           res(ev.data);
       };
       this.worker.addEventListener('message', listener);
       this.worker.postMessage(request);
-    });
+    }).catch(err => console.error(err));
   }
 }