comparison src/app/waveform/waveform.component.ts @ 118:5a4cd7add25a

Update colour mappers to slightly changed API; add green & sunset
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 14 Mar 2017 11:57:21 +0000
parents b8627a18c72d
children 7170e6ca2206
comparison
equal deleted inserted replaced
117:b8627a18c72d 118:5a4cd7add25a
158 } 158 }
159 159
160 interpolatingMapper(hexColours) { 160 interpolatingMapper(hexColours) {
161 const colours = hexColours.map(n => { 161 const colours = hexColours.map(n => {
162 const i = parseInt(n, 16); 162 const i = parseInt(n, 16);
163 return [ (i >> 16) & 255, (i >> 8) & 255, i & 255, 255 ]; 163 return [ ((i >> 16) & 255) / 255.0,
164 ((i >> 8) & 255) / 255.0,
165 ((i) & 255) / 255.0 ];
164 }); 166 });
165 const last = colours.length - 1; 167 const last = colours.length - 1;
166 return (value => { 168 return (value => {
167 // value must be in the range [0,1]. We quantize to 256 levels,
168 // as the PNG encoder deep inside uses a limited palette for
169 // simplicity. Should document this for the mapper. Also that
170 // individual colour values should be integers
171 value = Math.round(value * 255) / 255;
172 const m = value * last; 169 const m = value * last;
173 if (m >= last) { 170 if (m >= last) {
174 return colours[last]; 171 return colours[last];
175 } 172 }
176 if (m <= 0) { 173 if (m <= 0) {
179 const base = Math.floor(m); 176 const base = Math.floor(m);
180 const prop0 = base + 1.0 - m; 177 const prop0 = base + 1.0 - m;
181 const prop1 = m - base; 178 const prop1 = m - base;
182 const c0 = colours[base]; 179 const c0 = colours[base];
183 const c1 = colours[base+1]; 180 const c1 = colours[base+1];
184 return [ Math.round(c0[0] * prop0 + c1[0] * prop1), 181 return [ c0[0] * prop0 + c1[0] * prop1,
185 Math.round(c0[1] * prop0 + c1[1] * prop1), 182 c0[1] * prop0 + c1[1] * prop1,
186 Math.round(c0[2] * prop0 + c1[2] * prop1), 183 c0[2] * prop0 + c1[2] * prop1 ];
187 255 ];
188 }); 184 });
189 } 185 }
190 186
191 iceMapper() { 187 iceMapper() {
192 let hexColours = [ 188 let hexColours = [
194 "ffffff", "ffff00", "f7fcf0", "e0f3db", "ccebc5", "a8ddb5", 190 "ffffff", "ffff00", "f7fcf0", "e0f3db", "ccebc5", "a8ddb5",
195 "7bccc4", "4eb3d3", "2b8cbe", "0868ac", "084081", "042040" 191 "7bccc4", "4eb3d3", "2b8cbe", "0868ac", "084081", "042040"
196 ]; 192 ];
197 hexColours.reverse(); 193 hexColours.reverse();
198 return this.interpolatingMapper(hexColours); 194 return this.interpolatingMapper(hexColours);
195 }
196
197 hsv2rgb(h, s, v) { // all values in range [0, 1]
198 const i = Math.floor(h * 6);
199 const f = h * 6 - i;
200 const p = v * (1 - s);
201 const q = v * (1 - f * s);
202 const t = v * (1 - (1 - f) * s);
203 let r = 0, g = 0, b = 0;
204 switch (i % 6) {
205 case 0: r = v, g = t, b = p; break;
206 case 1: r = q, g = v, b = p; break;
207 case 2: r = p, g = v, b = t; break;
208 case 3: r = p, g = q, b = v; break;
209 case 4: r = t, g = p, b = v; break;
210 case 5: r = v, g = p, b = q; break;
211 }
212 return [ r, g, b ];
213 }
214
215 greenMapper() {
216 const blue = 0.6666;
217 const pieslice = 0.3333;
218 return (value => {
219 const h = blue - value * 2.0 * pieslice;
220 const s = 0.5 + value / 2.0;
221 const v = value;
222 return this.hsv2rgb(h, s, v);
223 });
224 }
225
226 sunsetMapper() {
227 return (value => {
228 let r = (value - 0.24) * 2.38;
229 let g = (value - 0.64) * 2.777;
230 let b = (3.6 * value);
231 if (value > 0.277) b = 2.0 - b;
232 return [ r, g, b ];
233 });
199 } 234 }
200 235
201 renderWaveform(buffer: AudioBuffer): void { 236 renderWaveform(buffer: AudioBuffer): void {
202 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2; 237 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2;
203 const waveTrack = this.timeline.getTrackById('wave'); 238 const waveTrack = this.timeline.getTrackById('wave');
344 renderSpectrogram(buffer: AudioBuffer): void { 379 renderSpectrogram(buffer: AudioBuffer): void {
345 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2; 380 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2;
346 const gridTrack = this.timeline.getTrackById('grid'); 381 const gridTrack = this.timeline.getTrackById('grid');
347 382
348 const spectrogramLayer = new wavesUI.helpers.SpectrogramLayer(buffer, { 383 const spectrogramLayer = new wavesUI.helpers.SpectrogramLayer(buffer, {
349 top: 10, 384 top: height * 0.05,
350 height: height * 0.9, 385 height: height * 0.9,
351 stepSize: 512, 386 stepSize: 512,
352 fftSize: 1024 387 fftSize: 1024,
388 normalise: 'none',
389 mapper: this.sunsetMapper()
353 }); 390 });
354 this.addLayer(spectrogramLayer, gridTrack, this.timeline.timeContext); 391 this.addLayer(spectrogramLayer, gridTrack, this.timeline.timeContext);
355 392
356 this.timeline.tracks.update(); 393 this.timeline.tracks.update();
357 } 394 }
360 private renderFeatures(extracted: SimpleResponse, colour: Colour): void { 397 private renderFeatures(extracted: SimpleResponse, colour: Colour): void {
361 if (!extracted.hasOwnProperty('features') || !extracted.hasOwnProperty('outputDescriptor')) return; 398 if (!extracted.hasOwnProperty('features') || !extracted.hasOwnProperty('outputDescriptor')) return;
362 if (!extracted.features.hasOwnProperty('shape') || !extracted.features.hasOwnProperty('data')) return; 399 if (!extracted.features.hasOwnProperty('shape') || !extracted.features.hasOwnProperty('data')) return;
363 const features: FeatureCollection = (extracted.features as FeatureCollection); 400 const features: FeatureCollection = (extracted.features as FeatureCollection);
364 const outputDescriptor = extracted.outputDescriptor; 401 const outputDescriptor = extracted.outputDescriptor;
365 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; 402 const height = this.trackDiv.nativeElement.getBoundingClientRect().height / 2;
366 const waveTrack = this.timeline.getTrackById('main'); 403 const waveTrack = this.timeline.getTrackById('wave');
367 404
368 // TODO refactor all of this 405 // TODO refactor all of this
369 switch (features.shape) { 406 switch (features.shape) {
370 case 'vector': { 407 case 'vector': {
371 const stepDuration = (features as FixedSpacedFeatures).stepDuration; 408 const stepDuration = (features as FixedSpacedFeatures).stepDuration;
500 const gain = (targetValue > 0.0 ? (1.0 / targetValue) : 1.0); 537 const gain = (targetValue > 0.0 ? (1.0 / targetValue) : 1.0);
501 console.log("setting gain to " + gain); 538 console.log("setting gain to " + gain);
502 const matrixEntity = new wavesUI.utils.PrefilledMatrixEntity(matrixData); 539 const matrixEntity = new wavesUI.utils.PrefilledMatrixEntity(matrixData);
503 let matrixLayer = new wavesUI.helpers.MatrixLayer(matrixEntity, { 540 let matrixLayer = new wavesUI.helpers.MatrixLayer(matrixEntity, {
504 gain, 541 gain,
505 height: height * 0.8, 542 height: height * 0.9,
506 top: height * 0.1, 543 top: height * 0.05,
507 normalise: 'none', 544 normalise: 'none',
508 mapper: this.iceMapper() 545 mapper: this.iceMapper()
509 }); 546 });
510 this.colouredLayers.set(this.addLayer( 547 this.colouredLayers.set(this.addLayer(
511 matrixLayer, 548 matrixLayer,