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 }