comparison src/app/app.component.ts @ 203:f9088265a1fc

Some basic idea of a session - though barely. Add new items after opening a file and extracting features.
author Lucas Thompson <dev@lucas.im>
date Fri, 24 Mar 2017 11:08:32 +0000
parents ac57ddba8ba9
children 1db0bb28688b
comparison
equal deleted inserted replaced
202:038d248602d5 203:f9088265a1fc
6 import {FeatureExtractionService} from "./services/feature-extraction/feature-extraction.service"; 6 import {FeatureExtractionService} from "./services/feature-extraction/feature-extraction.service";
7 import {ExtractorOutputInfo} from "./feature-extraction-menu/feature-extraction-menu.component"; 7 import {ExtractorOutputInfo} from "./feature-extraction-menu/feature-extraction-menu.component";
8 import {DomSanitizer} from '@angular/platform-browser'; 8 import {DomSanitizer} from '@angular/platform-browser';
9 import {MdIconRegistry} from '@angular/material'; 9 import {MdIconRegistry} from '@angular/material';
10 import {Subscription} from "rxjs"; 10 import {Subscription} from "rxjs";
11 import {AnalysisItem} from "./analysis-item/analysis-item.component";
11 12
12 @Component({ 13 @Component({
13 selector: 'app-root', 14 selector: 'app-root',
14 templateUrl: './app.component.html', 15 templateUrl: './app.component.html',
15 styleUrls: ['./app.component.css'] 16 styleUrls: ['./app.component.css']
16 }) 17 })
17 export class AppComponent implements OnDestroy { 18 export class AppComponent implements OnDestroy {
18 audioBuffer: AudioBuffer; // TODO consider revising 19 audioBuffer: AudioBuffer; // TODO consider revising
19 canExtract: boolean; 20 canExtract: boolean;
20 isProcessing: boolean;
21 private onAudioDataSubscription: Subscription; 21 private onAudioDataSubscription: Subscription;
22 private analyses: AnalysisItem[]; // TODO some immutable state container describing entire session
23 private nRecordings: number; // TODO user control for naming a recording
24 private rootAudioUri: string;
22 25
23 constructor(private audioService: AudioPlayerService, 26 constructor(private audioService: AudioPlayerService,
24 private piperService: FeatureExtractionService, 27 private piperService: FeatureExtractionService,
25 private iconRegistry: MdIconRegistry, 28 private iconRegistry: MdIconRegistry,
26 private sanitizer: DomSanitizer) { 29 private sanitizer: DomSanitizer) {
30 this.analyses = [];
27 this.canExtract = false; 31 this.canExtract = false;
28 this.isProcessing = false; 32 this.nRecordings = 0;
29 iconRegistry.addSvgIcon( 33 iconRegistry.addSvgIcon(
30 'duck', 34 'duck',
31 sanitizer.bypassSecurityTrustResourceUrl('assets/duck.svg') 35 sanitizer.bypassSecurityTrustResourceUrl('assets/duck.svg')
32 ); 36 );
33 37
34 this.onAudioDataSubscription = this.audioService.audioLoaded$.subscribe( 38 this.onAudioDataSubscription = this.audioService.audioLoaded$.subscribe(
35 resource => { 39 resource => {
36 const wasError = (resource as AudioResourceError).message != null; 40 const wasError = (resource as AudioResourceError).message != null;
37 if (wasError) { 41 if (wasError) {
38 this.isProcessing = false; 42 this.analyses.shift();
39 this.canExtract = false; 43 this.canExtract = false;
40 } else { 44 } else {
41 this.audioBuffer = (resource as AudioResource).samples; 45 this.audioBuffer = (resource as AudioResource).samples;
42 if (this.audioBuffer) { 46 if (this.audioBuffer) {
43 this.canExtract = true; 47 this.canExtract = true;
44 this.isProcessing = false;
45 } 48 }
46 } 49 }
47 } 50 }
48 ); 51 );
49 } 52 }
50 53
51 onFileOpened(file: File | Blob) { 54 onFileOpened(file: File | Blob) {
52 this.canExtract = false; 55 this.canExtract = false;
53 this.isProcessing = true; 56 const url = this.audioService.loadAudio(file);
54 this.audioService.loadAudio(file); 57 this.rootAudioUri = url; // TODO this isn't going to work to id previously loaded files
58
59 // TODO is it safe to assume it is a recording?
60 const title = (file instanceof File) ?
61 (file as File).name : `Recording ${this.nRecordings++}`;
62
63 if (this.analyses.filter(item => item.title === title).length > 0) {
64 // TODO this reveals how brittle the current name / uri based id is
65 // need something more robust, and also need to notify the user
66 // in a suitable way in the actual event of a duplicate file
67 console.warn('There is already a notebook based on this audio file.');
68 return;
69 }
70
71 // TODO re-ordering of items for display
72 // , one alternative is a Angular Pipe / Filter for use in the Template
73 this.analyses.unshift({
74 rootAudioUri: url,
75 hasSharedTimeline: true,
76 extractorKey: 'not:real',
77 isRoot: true,
78 title: title,
79 description: new Date().toLocaleString()
80 });
55 } 81 }
56 82
57 extractFeatures(outputInfo: ExtractorOutputInfo): void { 83 extractFeatures(outputInfo: ExtractorOutputInfo): void {
58 if (!this.canExtract || !outputInfo) return; 84 if (!this.canExtract || !outputInfo) return;
59 this.canExtract = false; 85 this.canExtract = false;
60 this.isProcessing = true; 86
87 this.analyses.unshift({
88 rootAudioUri: this.rootAudioUri,
89 hasSharedTimeline: true,
90 extractorKey: outputInfo.combinedKey,
91 isRoot: false,
92 title: outputInfo.name,
93 description: outputInfo.outputId
94 });
95
61 this.piperService.collect({ 96 this.piperService.collect({
62 audioData: [...Array(this.audioBuffer.numberOfChannels).keys()] 97 audioData: [...Array(this.audioBuffer.numberOfChannels).keys()]
63 .map(i => this.audioBuffer.getChannelData(i)), 98 .map(i => this.audioBuffer.getChannelData(i)),
64 audioFormat: { 99 audioFormat: {
65 sampleRate: this.audioBuffer.sampleRate, 100 sampleRate: this.audioBuffer.sampleRate,
67 }, 102 },
68 key: outputInfo.extractorKey, 103 key: outputInfo.extractorKey,
69 outputId: outputInfo.outputId 104 outputId: outputInfo.outputId
70 }).then(() => { 105 }).then(() => {
71 this.canExtract = true; 106 this.canExtract = true;
72 this.isProcessing = false;
73 }).catch(err => { 107 }).catch(err => {
74 this.canExtract = true; 108 this.canExtract = true;
75 this.isProcessing = false;
76 console.error(err) 109 console.error(err)
77 }); 110 });
78 } 111 }
79 112
80 ngOnDestroy(): void { 113 ngOnDestroy(): void {