diff --git a/app/components/arrangement-visual/track-clip.js b/app/components/arrangement-visual/track-clip.js index 212b8032..46bfa530 100644 --- a/app/components/arrangement-visual/track-clip.js +++ b/app/components/arrangement-visual/track-clip.js @@ -36,6 +36,7 @@ export default Clip.extend( audioMeta: Ember.computed.reads('track.audioMeta'), trackBpm: Ember.computed.reads('audioMeta.bpm'), trackBeatCount: Ember.computed.reads('audioMeta.beatCount'), + trackBarCount: Ember.computed.reads('audioMeta.barCount'), trackDuration: Ember.computed.reads('audioMeta.duration'), audioBinary: Ember.computed.reads('track.audioBinary'), audioBuffer: Ember.computed.reads('audioBinary.audioBuffer'), diff --git a/app/components/arrangement-visual/track-clip/wave.js b/app/components/arrangement-visual/track-clip/wave.js index d80ffded..ec83d22c 100644 --- a/app/components/arrangement-visual/track-clip/wave.js +++ b/app/components/arrangement-visual/track-clip/wave.js @@ -8,14 +8,26 @@ import { join } from 'ember-cli-d3/utils/d3'; import multiply from 'linx/lib/computed/multiply'; export default Ember.Component.extend( - GraphicSupport('peaks.[]', 'waveColor', 'height'), { + GraphicSupport('peaks.[]', 'waveColor', 'height', 'startBar', 'endBar', 'pxPerBeat', 'trackBarCount', 'showBarGrid'), { // required params peaks: null, + trackBarCount: 0, // optional params height: 125, waveColor: 'green', + showBarGrid: true, + + minX: 0, + maxX: multiply('trackBeatCount', 'pxPerBeat'), + + barScale: Ember.computed('startBar', 'endBar', 'minX', 'maxX', function () { + const domainMin = this.get('startBar'); + const domainMax = this.get('endBar'); + + return d3.scale.linear().domain([domainMin, domainMax]).range([this.get('minX'), this.get('maxX')]); + }).readOnly(), call(selection) { this._super.apply(this, arguments); diff --git a/app/components/mix-builder.js b/app/components/mix-builder.js index 96aa218d..e0fa202e 100644 --- a/app/components/mix-builder.js +++ b/app/components/mix-builder.js @@ -318,18 +318,6 @@ export default Ember.Component.extend( this.send('addTrack', track); }); }, - - // appendRandomTrack() { - // const mix = this.get('mix'); - // const tracks = this.get('searchTracks.content'); - // const randomTrack = _.sample(tracks.toArray()); - - // mix.appendTrack(randomTrack); - // }, - - // toggleShowVolumeAutomation() { - // this.toggleProperty('showVolumeAutomation'); - // }, }, // TODO(TECHDEBT): make this work with query param for sleected transition? @@ -350,10 +338,11 @@ export default Ember.Component.extend( // get default quantization // TODO(TECHDEBT): does this make sense to always say? how to tell if this event is active? - let defaultQuantization = this.get('selectedQuantization'); + const defaultQuantization = this.get('selectedQuantization'); const isAltKeyHeld = Ember.get(d3, 'event.sourceEvent.altKey') || Ember.get(d3, 'event.altKey'); const isCtrlKeyHeld = Ember.get(d3, 'event.sourceEvent.ctrlKey') || Ember.get(d3, 'event.ctrlKey') || Ember.get(d3, 'event.sourceEvent.metaKey') || Ember.get(d3, 'event.metaKey'); + if (isAltKeyHeld) { quantization = SAMPLE_QUANTIZATION; } else if (isCtrlKeyHeld) { diff --git a/app/components/mix-builder/precision-controls/track.js b/app/components/mix-builder/precision-controls/track.js index f0968919..2050a24e 100644 --- a/app/components/mix-builder/precision-controls/track.js +++ b/app/components/mix-builder/precision-controls/track.js @@ -9,14 +9,50 @@ export default Ember.Component.extend({ // optional params jumpTrackTask: null, jumpTrack: Ember.K, + quantizeBeat: Ember.K, + // internal params track: Ember.computed.reads('clip.track'), actions: { analyzeTrack() { const analyzeTask = this.get('track.analyzeTask'); analyzeTask.perform(); - } + }, + + setGrid() { + Ember.RSVP.resolve(this.get('clip')).then((clip) => { + const beat = this.get('clip.arrangement.metronome.seekBeat'); + const time = clip.getAudioTimeFromArrangementBeat(beat); + + const audioMeta = this.get('track.audioMeta.content'); + audioMeta.set('barGridTime', time); + // clip.setProperties({ + // audioStartTime: time, + // }); + }); + }, + + resetDownbeat() { + const clip = this.get('clip.content') || this.get('clip'); + + const prevStartTime = clip.get('audioStartTime'); + const beatGrid = this.get('track.audioMeta.beatGrid'); + const newStartTime = beatGrid.timeToQuantizedDownbeatTime(prevStartTime); + + console.log("QUANTIZE OLD", beatGrid.timeToBar(prevStartTime)) + console.log("QUANTIZE NEW", newStartTime) + + clip.setProperties({ + audioStartTime: newStartTime, + }); + }, + + setDownbeat() { + const audioMeta = this.get('track.audioMeta.content'); + + audioMeta.set('barGridTime', this.get('clip.audioStartTime')); + }, } }); diff --git a/app/models/track/audio-meta.js b/app/models/track/audio-meta.js index a4985412..e66bde9d 100644 --- a/app/models/track/audio-meta.js +++ b/app/models/track/audio-meta.js @@ -101,7 +101,7 @@ export default DS.Model.extend( bpm: DS.attr('number'), timeSignature: DS.attr('number', { defaultValue: 4 }), key: DS.attr('number'), - keyText: DS.attr('string'), // TODO(TECHDEBT) + keyText: DS.attr('string'), // TODO(TECHDEBT): dedupe with key, mode fields mode: DS.attr('number'), loudness: DS.attr('number'), barGridTime: DS.attr('number', { defaultValue: 0 }), @@ -120,6 +120,7 @@ export default DS.Model.extend( this.set('barGridTime', this.get('barGridTime') + value); }, + // TODO(TECHDEBT) // // calculate gain from loudness (decibels) // gain: Ember.computed('loudness', { // get() { @@ -176,17 +177,15 @@ export default DS.Model.extend( }), centerBeat: add('startBeat', 'halfBeatCount'), + barCount: Ember.computed('beatCount', 'timeSignature', function() { + return this.get('beatCount') / this.get('timeSignature'); + }), + firstWholeBeat: 0, firstWholeBar: 0, lastWholeBeat: computedBarToBeat('beatGrid', 'lastWholeBar'), lastWholeBar: computedQuantizeBar('beatGrid', 'endBar'), - // TODO: implement this, and move to audio-meta/beat-grid? - // amount by which echonest analysis is off from the downbeats - // calculated by diff from echonest section markers and the grid marker - echonestBeatOffset: Ember.computed('beatGrid.beatScale', 'beatGrid.barScale', function() { - }), - destroyMarkers: function() { return this.get('markers').then((markers) => { return Ember.RSVP.all(markers.map((marker) => { diff --git a/app/models/track/audio-meta/beat-grid.js b/app/models/track/audio-meta/beat-grid.js index 2d53e522..12761cb5 100644 --- a/app/models/track/audio-meta/beat-grid.js +++ b/app/models/track/audio-meta/beat-grid.js @@ -73,6 +73,10 @@ export default Ember.Object.extend({ return this.quantizeBar(this.timeToBar(time)); }, + timeToQuantizedDownbeatTime(time) { + return this.barToTime(this.timeToQuantizedBar(time)); + }, + // Beat Scale // domain is time [s] // range is beats [b] @@ -90,6 +94,7 @@ export default Ember.Object.extend({ quantizeBeatScaleRange: Ember.computed('beatScaleRange', function() { let beatScale = this.get('beatScale'); let [rangeMin, rangeMax] = beatScale.get('range'); + // TODO: i think below line is deprecated, and can be removed? // return d3.range(Math.ceil(rangeMin), Math.floor(rangeMax), 1); return [Math.ceil(rangeMin), Math.floor(rangeMax)]; }), @@ -128,7 +133,7 @@ export default Ember.Object.extend({ return timeToBeat(this.get('duration'), this.get('bpm')); }), - // the time of the first actual beat in the raw audio file + // the time of the first actual bar in the raw audio file // TODO(MULTIGRID): this supposes a constant bpm in the audio file firstBarOffset: Ember.computed('barGridTime', 'bpm', 'timeSignature', function() { const bpm = this.get('bpm'); @@ -136,14 +141,19 @@ export default Ember.Object.extend({ const secondsPerBeat = bpmToSpb(bpm); const secondsPerBar = secondsPerBeat * timeSignature; + console.log('calculating firstBarOffset') + let firstBarOffsetTime = this.get('barGridTime'); + console.log('barGridTime', firstBarOffsetTime) if (isValidNumber(bpm) && isValidNumber(timeSignature) && isValidNumber(firstBarOffsetTime)) { while ((firstBarOffsetTime - secondsPerBar) >= 0) { firstBarOffsetTime -= secondsPerBar; } + console.log('firstBarOffsetTime', firstBarOffsetTime) return firstBarOffsetTime * secondsPerBar; } else { + console.log('no firstBarOffsetTime', 0) return 0; } }), diff --git a/app/styles/components/_arrangement-visual/track-clip.scss b/app/styles/components/_arrangement-visual/track-clip.scss index bf3843ab..04a458ad 100644 --- a/app/styles/components/_arrangement-visual/track-clip.scss +++ b/app/styles/components/_arrangement-visual/track-clip.scss @@ -24,3 +24,31 @@ .ArrangementVisualTrackClip-startOverlay, .ArrangementVisualTrackClip-endOverlay { fill: rgba(#000, 0.5); } + +.ArrangementVisualTrackClip-beatAxis, .ArrangementVisualTrackClip-barAxis { + height: 30px; + color: white; + stroke: white; + + text { + display: none; + } + + .data-visual { + width: 100%; + height: 100%; + } + + .tick line { + stroke-width: 1; + stroke: rgba(#f0f, 0.8); + } + + .domain { + fill: none; + } +} + +.ArrangementVisualTrackClip-barAxis { + stroke: rgba(#fff, 0.3); +} diff --git a/app/templates/components/arrangement-visual/track-clip.hbs b/app/templates/components/arrangement-visual/track-clip.hbs index c7906ff9..c3590f3b 100644 --- a/app/templates/components/arrangement-visual/track-clip.hbs +++ b/app/templates/components/arrangement-visual/track-clip.hbs @@ -1,15 +1,13 @@ -{{!-- {{arrangement-visual/track-clip/axis - select=select - clip=clip - pxPerBeat=pxPerBeat -}} - --}} - {{arrangement-visual/track-clip/wave select=select.TrackClip-wave isD3Visible=displayWaveform waveColor=waveColor transform=(if displayOverflowWaveform startOffsetTransform) + startBar=audioMeta.startBar + endBar=audioMeta.endBar + trackBarCount=trackBarCount + trackBeatCount=trackBeatCount + pxPerBeat=pxPerBeat peaks=trackPeaks height=height }} diff --git a/app/templates/components/arrangement-visual/track-clip/wave.hbs b/app/templates/components/arrangement-visual/track-clip/wave.hbs index fb5c4b15..b6ecff7d 100644 --- a/app/templates/components/arrangement-visual/track-clip/wave.hbs +++ b/app/templates/components/arrangement-visual/track-clip/wave.hbs @@ -1 +1,11 @@ +{{d3-axis + select=select.ArrangementVisualTrackClip-barAxis + isD3Visible=showBarGrid + transform=(svg-translate 0 height) + scale=barScale + orient="top" + ticks=trackBarCount + tickSize=height +}} + {{yield}} \ No newline at end of file diff --git a/app/templates/components/mix-builder/precision-controls.hbs b/app/templates/components/mix-builder/precision-controls.hbs index 8dd5ada9..de09a693 100644 --- a/app/templates/components/mix-builder/precision-controls.hbs +++ b/app/templates/components/mix-builder/precision-controls.hbs @@ -3,6 +3,7 @@ clip=selectedTransition.fromTrackClip jumpTrackTask=jumpTrackTask + quantizeBeat=(action quantizeBeat) jumpTrack=(action jumpTrack selectedTransition.fromTrackClip.mixItem) }} @@ -10,10 +11,10 @@
{{mix-builder/precision-controls/transition clip=selectedTransition.transitionClip - showAutomation=attrs.showAutomation + showAutomation=showAutomation - quantizeBeat=(action attrs.quantizeBeat) - toggleShowAutomation=(action attrs.toggleShowAutomation) + quantizeBeat=(action quantizeBeat) + toggleShowAutomation=(action toggleShowAutomation) }}
diff --git a/app/templates/components/mix-builder/precision-controls/track.hbs b/app/templates/components/mix-builder/precision-controls/track.hbs index 60431b00..287d50e3 100644 --- a/app/templates/components/mix-builder/precision-controls/track.hbs +++ b/app/templates/components/mix-builder/precision-controls/track.hbs @@ -38,6 +38,11 @@ Set Downbeat +
+ Set Grid +
+ {{!--
Downbeat {{track.audioMeta.barGridTime}}