gibberwocky
Version:
music sequencing for Live and Max/MSP
121 lines (94 loc) • 3.62 kB
JavaScript
const Utility = require( '../../utility.js' )
const $ = Utility.create
module.exports = ( patternObject, marker, className, cm, track ) => {
let val ='/* ' + patternObject.values.join('') + ' */',
pos = marker.find(),
end = Object.assign( {}, pos.to ),
annotationStartCh = pos.from.ch + 3,
annotationEndCh = annotationStartCh + 1,
memberAnnotationStart = Object.assign( {}, pos.from ),
memberAnnotationEnd = Object.assign( {}, pos.to ),
initialized = false,
markStart = null,
commentMarker,
currentMarker, chEnd
end.ch = pos.from.ch + val.length
pos.to.ch -= 1
cm.replaceRange( val, pos.from, pos.to )
patternObject.commentMarker = cm.markText( pos.from, end, { className, atomic:false })
track.markup.textMarkers[ className ] = {}
let mark = () => {
// first time through, use the position given to us by the parser
let range,start, end
if( initialized === false ) {
memberAnnotationStart.ch = annotationStartCh
memberAnnotationEnd.ch = annotationEndCh
initialized = true
}else{
// after the first time through, every update to the pattern store the current
// position of the first element (in markStart) before replacing. Use this to generate position
// info. REPLACING TEXT REMOVES TEXT MARKERS.
range = markStart
start = range.from
memberAnnotationStart.ch = start.ch
memberAnnotationEnd.ch = start.ch + 1
}
for( let i = 0; i < patternObject.values.length; i++ ) {
track.markup.textMarkers[ className ][ i ] = cm.markText(
memberAnnotationStart, memberAnnotationEnd,
{ 'className': `${className}_${i}` }
)
memberAnnotationStart.ch += 1
memberAnnotationEnd.ch += 1
}
if( start !== undefined ) {
start.ch -= 3
end = Object.assign({}, start )
end.ch = memberAnnotationEnd.ch + 3
patternObject.commentMarker = cm.markText( start, end, { className, atomic:true })
}
}
mark()
// XXX: there's a bug when you sequence pattern transformations, and then insert newlines ABOVE the annotation
let count = 0, span, update, activeSpans = []
update = () => {
let currentIdx = count++ % patternObject.values.length
if( span !== undefined ) {
span.remove( 'euclid0' )
}
let spanName = `.${className}_${currentIdx}`,
currentValue = patternObject.values[ currentIdx ]
span = $( spanName )
// deliberate ==
if( currentValue == 1 ) {
span.add( 'euclid1' )
activeSpans.push( span )
setTimeout( ()=> {
activeSpans.forEach( _span => _span.remove( 'euclid1' ) )
activeSpans.length = 0
}, 50 )
}else{
span.add( 'euclid0' )
}
}
patternObject._onchange = () => {
let delay = Utility.beatsToMs( 1, Gibber.Scheduler.bpm )
markStart = track.markup.textMarkers[ className ][ 0 ].find()
Gibber.Environment.animationScheduler.add( () => {
for( let i = 0; i < patternObject.values.length; i++ ) {
let markerCh = track.markup.textMarkers[ className ][ i ],
pos = markerCh.find()
marker.doc.replaceRange( '' + patternObject.values[ i ], pos.from, pos.to )
}
mark()
}, delay )
}
patternObject.clear = () => {
const commentPos = patternObject.commentMarker.find()
// if this gets called twice...
if( commentPos === undefined ) return
cm.replaceRange( '', commentPos.from, { line:commentPos.to.line, ch:commentPos.to.ch+1 } )
patternObject.commentMarker.clear()
}
return update
}