Mercurial > hg > ugly-duckling
comparison src/app/spectrogram/Spectrogram.ts @ 236:53ea6406d601
Generate new project with latest @angular/cli, including Angular 4.
author | Lucas Thompson <dev@lucas.im> |
---|---|
date | Tue, 25 Apr 2017 20:01:09 +0100 |
parents | 19ca3aaf7807 |
children | 6a83df5029fe |
comparison
equal
deleted
inserted
replaced
235:76f2cd2c5a68 | 236:53ea6406d601 |
---|---|
1 /** | 1 /** |
2 * Created by lucast on 16/03/2017. | 2 * Created by lucast on 16/03/2017. |
3 */ | 3 */ |
4 import {RealFft, KissRealFft} from "piper/fft/RealFft"; | 4 import {RealFft, KissRealFft} from 'piper/fft/RealFft'; |
5 import {hann} from "piper/FftUtilities"; | 5 import {hann} from 'piper/FftUtilities'; |
6 import {Framing} from "piper"; | 6 import {Framing} from 'piper'; |
7 import Waves from 'waves-ui'; | 7 import Waves from 'waves-ui'; |
8 | 8 |
9 class SpectrogramEntity extends Waves.utils.MatrixEntity { | 9 class SpectrogramEntity extends Waves.utils.MatrixEntity { |
10 | 10 |
11 private samples: Float32Array; | 11 private samples: Float32Array; |
21 super(); | 21 super(); |
22 this.samples = samples; | 22 this.samples = samples; |
23 this.sampleRate = sampleRate; | 23 this.sampleRate = sampleRate; |
24 this.framing = options; | 24 this.framing = options; |
25 this.real = new Float32Array(this.framing.blockSize); | 25 this.real = new Float32Array(this.framing.blockSize); |
26 this.nCols = Math.floor(this.samples.length / this.framing.stepSize); //!!! not correct | 26 this.nCols = Math.floor(this.samples.length / this.framing.stepSize); // !!! not correct |
27 this.columnHeight = Math.round(this.framing.blockSize / 2) + 1; | 27 this.columnHeight = Math.round(this.framing.blockSize / 2) + 1; |
28 this.fft = new KissRealFft(this.framing.blockSize); | 28 this.fft = new KissRealFft(this.framing.blockSize); |
29 this.window = hann(this.framing.blockSize); | 29 this.window = hann(this.framing.blockSize); |
30 } | 30 } |
31 | 31 |
42 } | 42 } |
43 | 43 |
44 getStepDuration(): number { | 44 getStepDuration(): number { |
45 return this.framing.stepSize / this.sampleRate; | 45 return this.framing.stepSize / this.sampleRate; |
46 } | 46 } |
47 | 47 |
48 getColumn(n: number): Float32Array { | 48 getColumn(n: number): Float32Array { |
49 | 49 |
50 const startSample = n * this.framing.stepSize; | 50 const startSample = n * this.framing.stepSize; |
51 const sz = this.framing.blockSize; | 51 const sz = this.framing.blockSize; |
52 | 52 |
66 const h = this.getColumnHeight(); | 66 const h = this.getColumnHeight(); |
67 const col = new Float32Array(h); | 67 const col = new Float32Array(h); |
68 | 68 |
69 const scale = 1.0 / Math.sqrt(sz); | 69 const scale = 1.0 / Math.sqrt(sz); |
70 for (let i = 0; i < h; ++i) { | 70 for (let i = 0; i < h; ++i) { |
71 const re : number = complex[i*2] * scale; | 71 const re: number = complex[i * 2] * scale; |
72 const im : number = complex[i*2+1] * scale; | 72 const im: number = complex[i * 2 + 1] * scale; |
73 const mag = Math.sqrt(re * re + im * im); | 73 col[i] = Math.sqrt(re * re + im * im); |
74 col[i] = mag; | |
75 } | 74 } |
76 | 75 |
77 return col; | 76 return col; |
78 } | 77 } |
79 } | 78 } |
80 | 79 |
81 export class WavesSpectrogramLayer extends Waves.core.Layer { | 80 export class WavesSpectrogramLayer extends Waves.core.Layer { |
82 constructor(buffer: AudioBuffer, | 81 constructor(bufferIn: AudioBuffer, |
83 options: Framing & Object) { | 82 options: Framing & Object) { |
84 | 83 |
85 const defaults = { | 84 const defaults = { |
86 normalise: 'hybrid', | 85 normalise: 'hybrid', |
87 gain: 40.0, | 86 gain: 40.0, |
93 const mergedOptions: Framing & Object & {channel: number} = | 92 const mergedOptions: Framing & Object & {channel: number} = |
94 Object.assign({}, defaults, options); | 93 Object.assign({}, defaults, options); |
95 | 94 |
96 const getSamples = ((buffer, channel) => { | 95 const getSamples = ((buffer, channel) => { |
97 const nch = buffer.numberOfChannels; | 96 const nch = buffer.numberOfChannels; |
98 if (channel >= 0 || nch == 1) { | 97 if (channel >= 0 || nch === 1) { |
99 if (channel < 0) channel = 0; | 98 if (channel < 0) { |
100 return buffer.getChannelData(channel); | 99 channel = 0; |
100 } | |
101 return buffer.getChannelData(channel); | |
101 } else { | 102 } else { |
102 const before = performance.now(); | 103 const before = performance.now(); |
103 console.log("mixing down " + nch + " channels for spectrogram..."); | 104 console.log('mixing down ' + nch + ' channels for spectrogram...'); |
104 const mixed = Float32Array.from(buffer.getChannelData(0)); | 105 const mixed = Float32Array.from(buffer.getChannelData(0)); |
105 const n = mixed.length; | 106 const n = mixed.length; |
106 for (let ch = 1; ch < nch; ++ch) { | 107 for (let ch = 1; ch < nch; ++ch) { |
107 const buf = buffer.getChannelData(ch); | 108 const buf = buffer.getChannelData(ch); |
108 for (let i = 0; i < n; ++i) mixed[i] += buf[i]; | 109 for (let i = 0; i < n; ++i) { |
109 } | 110 mixed[i] += buf[i]; |
110 const scale = 1.0 / nch; | 111 } |
111 for (let i = 0; i < n; ++i) mixed[i] *= scale; | 112 } |
112 console.log("done in " + (performance.now() - before) + "ms"); | 113 const scale = 1.0 / nch; |
113 return mixed; | 114 for (let i = 0; i < n; ++i) { |
115 mixed[i] *= scale; | |
116 } | |
117 console.log('done in ' + (performance.now() - before) + 'ms'); | |
118 return mixed; | |
114 } | 119 } |
115 }); | 120 }); |
116 | 121 |
117 super('entity', | 122 super( |
118 new SpectrogramEntity(getSamples(buffer, mergedOptions.channel), | 123 'entity', |
119 mergedOptions, | 124 new SpectrogramEntity(getSamples(bufferIn, mergedOptions.channel), |
120 buffer.sampleRate), | 125 mergedOptions, |
121 mergedOptions); | 126 bufferIn.sampleRate), |
127 mergedOptions | |
128 ); | |
122 | 129 |
123 this.configureShape(Waves.shapes.Matrix, {}, mergedOptions); | 130 this.configureShape(Waves.shapes.Matrix, {}, mergedOptions); |
124 } | 131 } |
125 } | 132 } |