-- Version 0.51 assert((nwc.VERSIONDATE or '00000000') >= '20161207', 'This plugin requires version 2.75a') --[[----------------------------------------------------------------------------------------- CueStaff.test This object can be used to add special lines that span across a selection of notes. An optional text instruction can accompany the line. @Span This sets the number of notes that will encompass the line span. You can use a fractional value to extend the line beyond the target note. @Scale ___ @Pen This sets the pen style for the line. @PenW This sets the thickness for the line. @Offset ___ @DashLeft ___ @DashBars ___ @DashRight ___ --]]----------------------------------------------------------------------------------------- local userObjTypeName = ... local _spec = { {id='Span', label='Span', type='int', default=5, min=1, max=2000}, {id='Scale', label='Sc&ale', type='float', default=0.75, min=0.2, max=5, step=0.1}, {id='Offset', label='Offset', type='float', default=15, min=-100, max=100, step=0.5}, {id='Overhang', label='O&verhang', type='float', default=1, min=-100, max=100, step=0.5}, {id='DashLeft', label='Connect on &left', type='bool', default=false }, {id='DashBars', label='Connect &bars', type='bool', default=true }, {id='DashRight', label='Connect on &right', type='bool', default=false }, {id='Pen', label='&Line Type', type='enum', default=nwc.txt.DrawPenStyle[1], list=nwc.txt.DrawPenStyle}, {id='PenWidth', label='T&hickness', type='float', default=1, min=0.1, max=4, step=0.1}, } local function _create(t) t.Class = 'Span' end local function _span(t) return t.Span end --[[-- The audit sets the object Class to Span if the line crosses a bar. This allows the line to span through multiple printed systems. --]]-- local function _audit(t) ------ -- Overlap property is no longer needed ------ t.Overlap = nil ------ ------ local barSpan = (idx:find('span', _span(t)) or idx:find('last')) and idx:find('prior', 'bar') and (idx:indexOffset() > 0) ------ t.Class = barSpan and 'Span' or 'Standard' end local function _spin(t, dir) t.Span = t.Span + dir _audit(t) end local firstItem = nwcdraw.user.new() local item = nwcdraw.user.new() local lastItem = nwcdraw.user.new() ---- local draw, drawpos, idx = nwcdraw, nwcdraw.user, nwc.ntnidx local function mirrorStaffLines(y, scale, x1, x2, lines) y = y - scale * (lines - 1) local yBottom = y for i = 1, lines do nwcdraw.line(x1, y, x2, y) y = y + scale * 2 end return yBottom, y - scale * 2 end local noteHeadChar = { Whole='i', Half='j', Other='k' } local accidentalChar = { ['']='', ['#']='e', ['b']='f', ['n']='g', ['x']='h', ['v']='i' } local scaleSize local function splitPitchPos(pitchPos) -- nwc.debug('splitPitchPos(pitchPos)', pitchPos) return string.match(pitchPos, '([#bnxv]?)([-]?%d+)([oxXzyYabcdefgh])(%^?)') end local function drawNoteHead(x, y, alignment, headChar, durBase, dots, acc, accX) -- nwc.debug('drawNoteHead(x, y, alignment, headChar, durBase, dots, accHead, accX)', x, y, alignment, headChar, durBase, dots, accHead, accX) nwcdraw.alignText('baseline', alignment) nwcdraw.moveTo(x, y) nwcdraw.text(noteHeadChar[durBase] or noteHeadChar.Other) nwcdraw.alignText('baseline', 'left') nwcdraw.moveTo(accX, y) nwcdraw.text(accidentalChar[acc]) end local function drawChord(offset, fontsize, scale, item) nwcdraw.setFontClass('StaffSymbols') nwcdraw.setFontSize(2 * scale * fontsize) local stemX, stemAnchorY = item:xyStemAnchor() local _, stemTipY = item:xyStemTip() local midX = item:xyAnchor() ------------------- leftX and (rightX or leftX + 0.5) or rightX + 0.5 for i = 1, item:noteCount() do local headX = item:xyNoteHead(i) local acc, pos, head, tie = splitPitchPos(item:notePitchPos(i)) local accX = item:xyNoteAccidental(i) drawNoteHead(stemX, offset + pos * scale, headX < stemX and 'right' or 'left', head, item:noteDurBase(i), item:isDotted(i), acc, stemX - 0.5) -- WRONG: accX is from 0, not from mid .... + accX * scale end nwcdraw.line(stemX, offset + stemAnchorY * scale, stemX, offset + stemTipY * scale) end local mirror = { Clef = function(offset, fontsize, scale, item, yBottom, yTop) end, Key = function(offset, fontsize, scale, item, yBottom, yTop) end, Bar = function(offset, fontsize, scale, item, yBottom, yTop) local x = item:xyAnchor() nwcdraw.line(x, yBottom, x, yTop) end, Ending = function(offset, fontsize, scale, item, yBottom, yTop) end, Instrument = function(offset, fontsize, scale, item, yBottom, yTop) end, TimeSig = function(offset, fontsize, scale, item, yBottom, yTop) end, Tempo = function(offset, fontsize, scale, item, yBottom, yTop) end, Dynamic = function(offset, fontsize, scale, item, yBottom, yTop) end, Note = function(offset, fontsize, scale, item, yBottom, yTop) drawChord(offset, fontsize, scale, item) end, Rest = function(offset, fontsize, scale, item, yBottom, yTop) end, Chord = function(offset, fontsize, scale, item, yBottom, yTop) drawChord(offset, fontsize, scale, item) end, SustainPedal = function(offset, fontsize, scale, item, yBottom, yTop) end, Flow = function(offset, fontsize, scale, item, yBottom, yTop) end, MPC = function(offset, fontsize, scale, item, yBottom, yTop) end, TempoVariance = function(offset, fontsize, scale, item, yBottom, yTop) end, DynamicVariance = function(offset, fontsize, scale, item, yBottom, yTop) end, PerformanceStyle = function(offset, fontsize, scale, item, yBottom, yTop) end, Text = function(offset, fontsize, scale, item, yBottom, yTop) end, RestChord = function(offset, fontsize, scale, item, yBottom, yTop) end, User = function(offset, fontsize, scale, item, yBottom, yTop) end, Spacer = function(offset, fontsize, scale, item, yBottom, yTop) end, RestMultiBar = function(offset, fontsize, scale, item, yBottom, yTop) end, Boundary = function(offset, fontsize, scale, item, yBottom, yTop) end, Marker = function(offset, fontsize, scale, item, yBottom, yTop) end, } local mirroredItems = { } for k, _ in pairs(mirror) do mirroredItems[#mirroredItems + 1] = k end local function _draw(t) local fontsize = nwcdraw.getFontSize() local _, penWidth = nwcdraw.getMicrons(1, t.PenWidth*0.2) firstItem:find('next') -- ??????????????????? 'item' local atSpanEnd = lastItem:find('span', _span(t), 'items') if not atSpanEnd then lastItem:find('last') end local lines = 5 ---- TODO: take from staff local x1 = firstItem:xyAnchor() - t.Overhang local x2 = lastItem:xyRight() + t.Overhang nwcdraw.setPen(t.Pen, penWidth) local yBottom, yTop = mirrorStaffLines(t.Offset, t.Scale, x1, x2, lines) --- nwc.debug('(yBottom, yTop)', yBottom, yTop) nwcdraw.setPen('dash', penWidth) if t.DashLeft then nwcdraw.line(x1, 4, x1, yBottom) end if t.DashBars then while item:find('next', 'bar') and item <= lastItem do local x = item:xyAnchor() nwcdraw.line(x, 4, x, yBottom) end end if t.DashRight then nwcdraw.line(x2, 4, x2, yBottom) end nwcdraw.setPen(t.Pen, penWidth) item:reset() while item:find('next', 'objType', table.unpack(mirroredItems)) and item <= lastItem do local m = mirror[item:objType()] m(t.Offset, fontsize, t.Scale, item, yBottom, yTop) end end return { ----- nwcut = {['Change Highlight of staff to white & back'] = 'ClipText'}, spec = _spec, create = _create, audit = _audit, spin = _spin, span = _span, draw = _draw, }