comparison src/app/Session.ts @ 460:ccce2c09502e

Manually cherry-pick various refactoring efforts from feature/basic-session-loading
author Lucas Thompson <dev@lucas.im>
date Fri, 30 Jun 2017 10:41:30 +0100
parents
children 2624bb55dbf6
comparison
equal deleted inserted replaced
459:8d561b6df2fa 460:ccce2c09502e
1 /**
2 * Created by lucast on 08/06/2017.
3 */
4 import {
5 Item,
6 RootAudioItem
7 } from './analysis-item/AnalysisItem';
8
9 export const exampleSession: SerialisedNotebook = {
10 root: {
11 id: '1',
12 hasSharedTimeline: true,
13 title: 'Drum Loop',
14 description: 'Remotely hosted audio file',
15 uri: 'https://piper-audio.github.io/waves-ui-piper/examples/assets/drum-loop.wav'
16 },
17 analyses: [
18 {
19 id: '2',
20 hasSharedTimeline: true,
21 extractorKey: 'vamp-example-plugins:amplitudefollower',
22 outputId: 'amplitude',
23 title: 'Amplitude',
24 description: 'amplitude'
25 },
26 {
27 id: '3',
28 hasSharedTimeline: true,
29 extractorKey: 'vamp-example-plugins:powerspectrum',
30 outputId: 'powerspectrum',
31 title: 'Simple Power Spectrum',
32 description: 'powerspectrum'
33 },
34
35 ]
36 };
37
38 export interface SerialisedAnalysisItem extends Item {
39 extractorKey: string;
40 outputId: string;
41 }
42
43 export interface SerialisedNotebook {
44 root: RootAudioItem;
45 analyses: SerialisedAnalysisItem[];
46 }
47
48 export type ResourceRetriever = (url: string) => Promise<Blob>;
49
50 export const downloadResource: ResourceRetriever = async (url) => {
51 const response = await fetch(url);
52 const mimeType = response.headers.get('content-type');
53 // Safari's fetch.blob implementation doesn't populate the type property
54 // causing the audio player to fail due to an unsupported type.
55 // Manually create a blob from an array buffer and the content type in
56 // the response object
57 const arrayBufferToBlob = async () => {
58 const arrayBuffer = await response.arrayBuffer();
59 return new Blob([arrayBuffer], {type: mimeType});
60 };
61 return mimeType ? arrayBufferToBlob() : response.blob();
62 };
63
64 export class PersistentStack<T> {
65 private stack: T[];
66 private history: T[][];
67
68 constructor() {
69 this.stack = [];
70 this.history = [];
71 }
72
73 shift(): T {
74 this.history.push([...this.stack]);
75 const item = this.stack[0];
76 this.stack = this.stack.slice(1);
77 return item;
78 }
79
80 unshift(item: T): number {
81 this.history.push([...this.stack]);
82 this.stack = [item, ...this.stack];
83 return this.stack.length;
84 }
85
86 findIndex(predicate: (value: T,
87 index: number,
88 array: T[]) => boolean): number {
89 return this.stack.findIndex(predicate);
90 }
91
92 filter(predicate: (value: T, index: number, array: T[]) => boolean): T[] {
93 return this.stack.filter(predicate);
94 }
95
96 get(index: number): T {
97 return this.stack[index];
98 }
99
100 set(index: number, value: T) {
101 this.history.push([...this.stack]);
102 this.stack = [
103 ...this.stack.slice(0, index),
104 value,
105 ...this.stack.slice(index + 1)
106 ];
107 }
108
109 map<U>(transform: (value: T, index: number, array: T[]) => U): U[] {
110 return this.stack.map(transform);
111 }
112
113 reduce<U>(reducer: (previousValue: U,
114 currentValue: T,
115 currentIndex: number,
116 array: T[]) => U,
117 initialValue: U): U {
118 return this.stack.reduce(reducer, initialValue);
119 }
120
121 remove(...indices: number[]) {
122 this.history.push([...this.stack]);
123 this.stack = this.stack.reduce((acc, item, i) => {
124 if (!indices.includes(i)) {
125 acc.push(item);
126 }
127 return acc;
128 }, [] as T[]);
129 }
130
131 toIterable(): Iterable<T> {
132 return this.stack;
133 }
134 }