Skip to content

Commit

Permalink
--wip--
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfbiter committed Oct 8, 2016
1 parent a30327c commit d349b9a
Show file tree
Hide file tree
Showing 17 changed files with 381 additions and 260 deletions.
16 changes: 8 additions & 8 deletions app/initializers/catch-errors.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Ember from 'ember';

// all uncaught errors will be caught here
// you can use `message` to make sure it's the error you're looking for
// returning true overrides the default window behaviour
window.onerror = function(message, file, lineNumber, columnNumber, error) {
console.warn(message, error && error.stack);
window.error = error;
return true;
};
// // all uncaught errors will be caught here
// // you can use `message` to make sure it's the error you're looking for
// // returning true overrides the default window behaviour
// window.onerror = function(message, file, lineNumber, columnNumber, error) {
// console.warn(message, error && error.stack);
// window.error = error;
// return true;
// };

export default {
name: 'CatchErrors',
Expand Down
29 changes: 16 additions & 13 deletions app/lib/soundtouch.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ FifoSampleBuffer.prototype.clear = function() {
//
// TODO(TECHDEBT): window.BUFFER_SIZE set by mix builder
window.MAX_BUFFER_SIZE = 16384;
window.BUFFER_SIZE = MAX_BUFFER_SIZE / 8;
window.BUFFER_SIZE = window.MAX_BUFFER_SIZE / 8;
const SAMPLE_DRIFT_TOLERANCE = 512;

export function SoundtouchBufferSource(buffer) {
Expand Down Expand Up @@ -69,17 +69,19 @@ SoundtouchBufferSource.prototype = {
}
};

export function createSoundtouchNode({ audioContext, filter, startTime, offsetTime, endTime, defaultTempo, defaultPitch }) {
console.log('createSoundtouchNode')
// TODO(TRACKMULTIGRID): audioBpm not a constant
export function createSoundtouchNode({ audioContext, filter, startTime, offsetTime, endTime, audioBpm, defaultPitch }) {
const channelCount = 2;
const windowBufferSize = window.BUFFER_SIZE;

if (!(audioContext && filter
&& isValidNumber(startTime) && isValidNumber(offsetTime) && isValidNumber(endTime))) {
if (!(audioContext && filter &&
isValidNumber(startTime) && isValidNumber(offsetTime) && isValidNumber(endTime))) {
Ember.Logger.warn('Must provide all params to createSoundtouchNode', endTime);
return;
}

audioBpm = isValidNumber(audioBpm) ? audioBpm : 128; // TODO(TECHDEBT): share default bpm

const samples = new Float32Array(windowBufferSize * channelCount);
const sampleRate = audioContext.sampleRate || 44100;
const startSample = ~~(offsetTime * sampleRate);
Expand All @@ -101,11 +103,15 @@ export function createSoundtouchNode({ audioContext, filter, startTime, offsetTi
const l = outputs[0][0];
const r = outputs[0][1];

// naively take first pitch and tempo values for this sample
// naively take first pitch value for this sample
const pitch = parameters.pitch && parameters.pitch[0];
const tempo = parameters.tempo && parameters.tempo[0];
const soundtouch = filter.pipe;

// TODO(MULTIGRID): need to minimize dspBufLength.
// is it possible to align dspBufLength with automation clip TICKs?
const syncBpm = parameters.bpm && parameters.bpm[0];
const tempo = (isValidNumber(syncBpm) && isValidNumber(audioBpm)) ? (syncBpm / audioBpm) : 1;

if (isValidNumber(pitch)) {
soundtouch.pitchSemitones = pitch;
}
Expand Down Expand Up @@ -158,14 +164,11 @@ export function createSoundtouchNode({ audioContext, filter, startTime, offsetTi
r[i] = (samples[filterFrame * 2 + 1] * isPlaying[i]) || 0;
filterFrame += isPlaying[i];
}
};
}

defaultPitch = parseFloat(defaultPitch);
defaultPitch = isValidNumber(defaultPitch) ? defaultPitch : 0;

defaultTempo = parseFloat(defaultTempo);
defaultTempo = isValidNumber(defaultTempo) ? defaultTempo : 1;

const node = new AudioWorkerNode(audioContext, onaudioprocess, {
numberOfInputs: 2,
numberOfOutputs: 2,
Expand All @@ -176,8 +179,8 @@ export function createSoundtouchNode({ audioContext, filter, startTime, offsetTi
defaultValue: defaultPitch,
},
{
name: 'tempo',
defaultValue: defaultTempo,
name: 'bpm',
defaultValue: 1,
},
{
name: 'isPlaying',
Expand Down
6 changes: 3 additions & 3 deletions app/lib/web-audio/soundtouch-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export default Ember.ObjectProxy.extend(
node: null, // set by `start` method, unset by `disconnect`
outputNode: null,

// TODO(V2): TODO(MULTIGRID): tempo, transpose dynamic
start(startTime, offsetTime, endTime, tempo, transpose) {
// TODO(V2): transpose dynamic
start(startTime, offsetTime, endTime, audioBpm, transpose) {
// Ember.Logger.log('currentTime', this.get('audioContext.currentTime'));
// Ember.Logger.log('startSource', startTime, offsetTime);
this.stop();
Expand All @@ -36,7 +36,7 @@ export default Ember.ObjectProxy.extend(
startTime,
offsetTime,
endTime,
defaultTempo: tempo,
audioBpm,
defaultPitch: transpose,
});
this.set('node', node);
Expand Down
140 changes: 0 additions & 140 deletions app/lib/web-audio/track-source-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Ember from 'ember';
import BufferSourceNode from './buffer-source-node';
import RequireAttributes from 'linx/lib/require-attributes';

// TODO(REFACTOR): create base track FX chain + audio source node + soundtouch node
export default BufferSourceNode.extend({

// params
Expand All @@ -17,142 +16,3 @@ export default BufferSourceNode.extend({
return '<linx@object-proxy:web-audio/track-source-node>';
},
});


/* global SimpleFilter:true */

// import SoundTouch from 'linx/lib/soundtouch';
// import { WebAudioBufferSource, getWebAudioNode } from 'linx/lib/soundtouch';

// TODO(REFACTOR) move into fx chain
// updateTempo: function() {
// var wavesurfer = this.get('wavesurfer');
// var tempo = this.get('tempo');
// if (wavesurfer) {
// wavesurfer.setTempo(tempo);
// }
// }.observes('wavesurfer', 'tempo'),

// updatePitch: function() {
// var wavesurfer = this.get('wavesurfer');
// var pitch = this.get('pitch');
// if (wavesurfer) {
// wavesurfer.setPitch(pitch);
// }
// }.observes('wavesurfer', 'pitch'),

// updateVolume: function() {
// var wavesurfer = this.get('wavesurfer');
// var volume = this.get('volume');
// if (wavesurfer) {

// // TODO(EASY): remove this check, only for two-way binding to input
// try {
// volume = parseFloat(volume);
// } catch(e) {}

// if (typeof volume !== 'number' || !volume) {
// volume = 0;
// }

// wavesurfer.setVolume(volume);
// }
// }.observes('wavesurfer', 'volume'),


// TODO(REFACTOR): figure this out
//
// Wavesurfer + SoundTouch Integration
//

// Wavesurfer.setTempo = function(tempo) {
// this.backend.setTempo(tempo);
// };

// Wavesurfer.setPitch = function(pitch) {
// this.backend.setPitch(pitch);
// };

// Wavesurfer.WebAudio.setTempo = function(tempo) {
// // Ember.Logger.log("setting tempo", tempo);
// if (typeof tempo !== 'number' || !tempo) {
// tempo = 1;
// }

// // update startPosition and lastPlay for new tempo
// this.startPosition += this.getPlayedTime();
// this.lastPlay = this.ac.currentTime;

// this.linxTempo = this.playbackRate = tempo;

// // update soundtouch tempo
// var soundtouch = this.soundtouch;
// if (soundtouch) {
// soundtouch.tempo = tempo;
// }
// };

// Wavesurfer.WebAudio.setPitch = function(pitch) {
// // Ember.Logger.log("setting pitch", pitch);

// // TODO: remove this check, only for two-way binding to input
// try {
// pitch = parseFloat(pitch);
// } catch(e) {

// }
// if (typeof pitch !== 'number') {
// pitch = 0;
// }

// this.linxPitch = pitch;

// // update soundtouch pitch
// var soundtouch = this.soundtouch;
// if (soundtouch) {
// soundtouch.pitchSemitones = pitch;
// }
// };

// // 'play' is equivalent to 'create and connect soundtouch source'
// Wavesurfer.WebAudio.play = function(start, end) {
// if (!this.isPaused()) {
// this.pause();
// }

// var adjustedTime = this.seekTo(start, end);
// start = adjustedTime.start;
// end = adjustedTime.end;
// this.scheduledPause = end;
// var startSample = ~~(start * this.ac.sampleRate);

// // init soundtouch
// this.soundtouch = new SoundTouch();
// this.setPitch(this.linxPitch);
// this.setTempo(this.linxTempo);

// // hook up soundtouch node
// this.soundtouchSource = new WebAudioBufferSource(this.buffer);
// this.soundtouchFilter = new SimpleFilter(this.soundtouchSource, this.soundtouch);
// this.soundtouchFilter.sourcePosition = startSample;
// this.soundtouchNode = getWebAudioNode(this.ac, this.soundtouchFilter);
// this.soundtouchNode.connect(this.analyser);

// this.setState(this.PLAYING_STATE);
// this.fireEvent('play');
// };

// // 'pause' is equivalent to 'disconnect soundtouch source'
// Wavesurfer.WebAudio.pause = function() {
// this.scheduledPause = null;
// this.startPosition += this.getPlayedTime();

// this.soundtouchNode && this.soundtouchNode.disconnect();

// this.setState(this.PAUSED_STATE);
// };

// // turn into no-op
// Wavesurfer.WebAudio.createSource = function() {};

// export default Wavesurfer;
32 changes: 15 additions & 17 deletions app/mixins/playable-arrangement.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import withDefault from 'linx/lib/computed/with-default';
import Metronome from './playable-arrangement/metronome';
import WebAudioMergerNode from 'linx/lib/web-audio/merger-node';
import computedObject from 'linx/lib/computed/object';
import BeatGrid from 'linx/models/track/audio-meta/beat-grid';
import BeatGrid from './playable-arrangement/beat-grid';
import { flatten, isValidNumber } from 'linx/lib/utils';
import GainNode from 'linx/lib/web-audio/gain-node';

Expand All @@ -15,7 +15,14 @@ export default Ember.Mixin.create(
RequireAttributes('clips', 'audioContext'),
ReadinessMixin('isPlayableArrangementReady'), {

// params
// required params
clips: null,
bpmScale: null, // or beatGrid
audioContext: null,

// optional params
outputNode: Ember.computed.reads('audioContext.destination'),

playpause(beat) {
this.get('metronome').playpause(beat);
},
Expand Down Expand Up @@ -44,20 +51,17 @@ export default Ember.Mixin.create(
this.get('metronome').seekToBeat(beat);
},

// optional params
outputNode: Ember.computed.reads('audioContext.destination'),
bpm: 128.0,

isPlaying: Ember.computed.reads('metronome.isPlaying'),
duration: Ember.computed.reads('beatGrid.duration'),

metronome: computedObject(Metronome, {
'audioContext': 'audioContext',
'arrangement': 'this'
'beatGrid': 'beatGrid',
}),

beatGrid: computedObject(BeatGrid, {
duration: 'duration',
bpm: 'bpm',
bpmScale: 'bpmScale',
beatCount: 'beatCount',
timeSignature: 'timeSignature',
}),

Expand All @@ -83,17 +87,11 @@ export default Ember.Mixin.create(
return this.get('beatCount') / this.get('timeSignature');
}),

// duration of arrangement in [s]
// TODO(MULTIGRID)
duration: Ember.computed('metronome.bpm', 'beatCount', function() {
return this.get('metronome').getDuration(0, this.get('beatCount'));
}),

getRemainingDuration() {
const metronome = this.get('metronome');
const beatGrid = this.get('beatGrid');
const beatCount = this.get('beatCount');
const currentBeat = this.getCurrentBeat();
return metronome.getDuration(currentBeat, beatCount - currentBeat);
return beatGrid.getDuration(currentBeat, beatCount - currentBeat);
},

getCurrentBeat() {
Expand Down
15 changes: 2 additions & 13 deletions app/mixins/playable-arrangement/automatable-clip/control.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,9 @@ export default function(audioParamPath) {

// optional params
description: '',
// isSuspended: false,
valueScale: Ember.computed(() => d3.scale.identity()),
defaultValue: 0,

// TODO(TECHDEBT): share more cleanly
valueScale: Ember.computed('type', function() {
switch (this.get('type')) {
case CONTROL_TYPE_DELAY_CUTOFF:
case CONTROL_TYPE_FILTER_HIGHPASS_CUTOFF:
case CONTROL_TYPE_FILTER_LOWPASS_CUTOFF:
return d3.scale.log().domain([20, 22050]).range([0, 1]);
default:
return d3.scale.identity();
}
}),
// isSuspended: false,

_initClipListeners: Ember.on('init', function() {
const clip = this.get('clip');
Expand Down
Loading

0 comments on commit d349b9a

Please sign in to comment.