Mercurial > hg > ugly-duckling
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 { |