Skip to content

Commit

Permalink
WIP: mix variable tempo
Browse files Browse the repository at this point in the history
WIP: fix scale issues
minor successS: got workaround for non-computing property in playable arrangement
  • Loading branch information
wolfbiter committed Oct 23, 2016
1 parent 622f1da commit 3d65de4
Show file tree
Hide file tree
Showing 28 changed files with 528 additions and 300 deletions.
1 change: 1 addition & 0 deletions app/components/mix-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export default Ember.Component.extend(

seekToBeat(beat) {
const quantizedBeat = this._quantizeBeat(beat);
console.log('seekToBeat', beat, quantizedBeat);

this.get('mix').seekToBeat(quantizedBeat);
this.trigger('seekToBeat', quantizedBeat);
Expand Down
1 change: 1 addition & 0 deletions app/components/mix-visual/track-clip.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default ArrangementVisualTrackClip.extend(
(currentAudioTime + MARKER_CLICK_WINDOW >= time);
});

// TODO(TRACKMULTIGRID): refactor to use dynamic beatgrids instead of static time
if (marker && isValidNumber(marker.time)) {
console.log('clicked marker', marker);

Expand Down
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
22 changes: 10 additions & 12 deletions app/lib/soundtouch.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ 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 DSP_BUFFER_LENGTH = 128;
const SAMPLE_DRIFT_TOLERANCE = 512;

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

export function createSoundtouchNode({ audioContext, filter, startTime, offsetTime, endTime, defaultTempo, defaultPitch }) {
console.log('createSoundtouchNode')
export function createSoundtouchNode({ audioContext, filter, startTime, offsetTime, endTime, 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;
}
Expand All @@ -87,6 +87,7 @@ export function createSoundtouchNode({ audioContext, filter, startTime, offsetTi
filter.sourcePosition = startSample;

const filterStartPosition = filter.position;
const soundtouch = filter.pipe;

function onaudioprocess({
type,
Expand All @@ -101,10 +102,9 @@ 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
// TODO(MULTIGRID): average tempo, pitch across buffer
const pitch = parameters.pitch && parameters.pitch[0];
const tempo = parameters.tempo && parameters.tempo[0];
const soundtouch = filter.pipe;

if (isValidNumber(pitch)) {
soundtouch.pitchSemitones = pitch;
Expand Down Expand Up @@ -158,26 +158,24 @@ 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,
bufferLength: windowBufferSize,
dspBufLength: DSP_BUFFER_LENGTH,
parameters: [
{
name: 'pitch',
defaultValue: defaultPitch,
},
{
name: 'tempo',
defaultValue: defaultTempo,
defaultValue: 1,
},
{
name: 'isPlaying',
Expand Down
2 changes: 1 addition & 1 deletion app/lib/web-audio/gain-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default Ember.ObjectProxy.extend(
const node = this.get('node');
const value = this.get('value');

console.log('update gain value', value, isValidNumber(value))
// console.log('update gain value', value, isValidNumber(value))
if (node && isValidNumber(value)) {
node.gain.value = value;
}
Expand Down
5 changes: 2 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, transpose) {
// Ember.Logger.log('currentTime', this.get('audioContext.currentTime'));
// Ember.Logger.log('startSource', startTime, offsetTime);
this.stop();
Expand All @@ -36,7 +36,6 @@ export default Ember.ObjectProxy.extend(
startTime,
offsetTime,
endTime,
defaultTempo: tempo,
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;
Loading

0 comments on commit 3d65de4

Please sign in to comment.