-- $NWCUT$CONFIG: FileText $ nwcut.setlevel(2) nwcut.status = nwcut.const.rc_Succes --nwcut.status = nwcut.const.rc_Report local POSNUMBER = 128 local progname = 'staffsplitter.lua' local ASI = 0 -- Active Staff Parameters local ASN = "UnDefined"; local CSI = 0 -- Current Staff Parameters local CSN = "UnDefined"; local HelpMsg = [[ This tool evaluates the current staff and each existing note is duplicated in its own staff. Enharmonic notations will be collected in the same staff. This tool can be executed several times (for different staves) ]] -------------------------------------- -- function midicalc -------------------------------------- local function midicalc (p_notepos,p_accidental,p_transposition) local lv_val lv_val = 0 if p_notepos == 0 then lv_val = lv_val + 0 end--if if p_notepos == 1 then lv_val = lv_val + 2 end--if if p_notepos == 2 then lv_val = lv_val + 4 end--if if p_notepos == 3 then lv_val = lv_val + 5 end--if if p_notepos == 4 then lv_val = lv_val + 7 end--if if p_notepos == 5 then lv_val = lv_val + 9 end--if if p_notepos == 6 then lv_val = lv_val + 11 end--if if p_accidental == 'z' then lv_val = lv_val + 0 end--if if p_accidental == '#' then lv_val = lv_val + 1 end--if if p_accidental == 'x' then lv_val = lv_val + 2 end--if if p_accidental == 'b' then lv_val = lv_val - 1 end--if if p_accidental == 'v' then lv_val = lv_val - 2 end--if lv_val = lv_val + p_transposition return lv_val end--function -------------------------------------- -- function decode_transposition -------------------------------------- local function decode_transposition () -- uses global variables : staff_instrument,current_instrument local lv_val lv_val = staff_instrument.Opts.Trans or 0 lv_val = lv_val + ( current_instrument.Opts.Trans or 0 ) return lv_val end--function -------------------------------------- -- function strip_tie (last character = ^) -------------------------------------- local function strip_tie (p_notepos) lv_notepos = tostring(p_notepos) if string.sub(lv_notepos,-1 ) == "^" then lv_notepos = string.sub(lv_notepos,1,string.len(lv_notepos)-1 ) ; end--if return lv_notepos end--function -------------------------------------- -- function decode_note -------------------------------------- local function decode_note (p_position_with_accidental) -- uses global arrays : measure_accidental, current_clef -- define accidental and relative position lv_tempstring = tostring(p_position_with_accidental) -- strip non numeric characters at the end (notehead info) while ( string.byte(string.sub(lv_tempstring,-1 )) < 48 or string.byte(string.sub(lv_tempstring,-1 )) > 57 ) do lv_tempstring = string.sub(lv_tempstring,1,string.len(lv_tempstring)-1 ) ; end--while lv_accidental = string.sub(lv_tempstring,1,1) lv_position = 0 if lv_accidental == 'v' or lv_accidental == 'b' or lv_accidental == 'n' or lv_accidental == '#' or lv_accidental == 'x' then lv_position = string.sub(lv_tempstring,2) + 0 ; else lv_position = lv_tempstring + 0 ; lv_accidental = 'z' ; end--if -- define middle note for clef -- |Clef|Type:Treble |Clef|Type:Bass |Clef|Type:Alto |Clef|Type:Tenor |Clef|Type:Treble|OctaveShift:Octave Up |Clef|Type:Treble|OctaveShift:Octave Down |Clef|Type:Percussion -- unless specified, the default type is always initialised to 'Treble' if current_clef.Opts.Type == 'Treble' then lv_relativeposition = 4*7 + 6 ; end--if if current_clef.Opts.Type == 'Alto' then lv_relativeposition = 4*7 + 0 ; end--if if current_clef.Opts.Type == 'Tenor' then lv_relativeposition = 3*7 + 5 ; end--if if current_clef.Opts.Type == 'Bass' then lv_relativeposition = 3*7 + 1 ; end--if if current_clef.Opts.Type == 'Percussion' then lv_relativeposition = 3*7 + 1 ; end--if -- define octaveshift if current_clef.Opts.OctaveShift == 'Octave Down' then lv_relativeposition = lv_relativeposition - 7 ; end--if if current_clef.Opts.OctaveShift == 'Octave Up' then lv_relativeposition = lv_relativeposition + 7 ; end--if -- define absolute position -- |Note|Dur:4th|Pos:3 |Note|Dur:4th|Pos:n3 |Note|Dur:4th|Pos:b3 |Note|Dur:4th|Pos:v3 |Note|Dur:4th|Pos:#3 |Note|Dur:4th|Pos:x3 |Note|Dur:4th|Pos:#20 lv_relativeposition = lv_relativeposition + lv_position -- define transposition transp = decode_transposition () -- calculate octave, note number, notename, midivalue lv_octave = math.floor(lv_relativeposition/7) lv_note = lv_relativeposition % 7 midivalue = 12 * lv_octave + midicalc (lv_note,lv_accidental,transp) if lv_note == 0 then lv_notename = 'C' end--if ; if lv_note == 1 then lv_notename = 'D' end--if ; if lv_note == 2 then lv_notename = 'E' end--if ; if lv_note == 3 then lv_notename = 'F' end--if ; if lv_note == 4 then lv_notename = 'G' end--if ; if lv_note == 5 then lv_notename = 'A' end--if ; if lv_note == 6 then lv_notename = 'B' end--if ; if lv_accidental == 'z' and measure_accidental[lv_notename] ~= 'z' then lv_accidental = measure_accidental[lv_notename] end--if if lv_accidental ~= 'z' then measure_accidental[lv_notename] = lv_accidental ; end--if if lv_octave < 0 then lv_notename = 'RRR'; lv_accidental ="" ; lv_octave =0 ; midivalue = 0 end--if midival_fixed = midivalue + 1000 return midivalue end -------------------------------------- -- reset measure_accidentals (at each barline / at each staff_accidental object) -------------------------------------- local function reset_measure_accidentals() measure_accidental.A=staff_accidentals.A measure_accidental.B=staff_accidentals.B measure_accidental.C=staff_accidentals.C measure_accidental.D=staff_accidentals.D measure_accidental.E=staff_accidentals.E measure_accidental.F=staff_accidentals.F measure_accidental.G=staff_accidentals.G end -------------------------------------- -- function eval_signature -------------------------------------- local function eval_signature(p_siglist) -- |Key|Signature:F#,C#,G#,D#|Tonic:C |Key|Signature:C|Tonic:A staff_accidentals.A="z" ; staff_accidentals.B="z" ; staff_accidentals.C="z" ; staff_accidentals.D="z" ; staff_accidentals.E="z" ; staff_accidentals.F="z" ; staff_accidentals.G="z" ; for i, v in pairs(p_siglist) do if string.len(i) < 1 or string.len(i) > 2 then print ("exception <1 or >2 ",i) end--if if string.len(i) == 2 then staff_accidentals[string.sub(i,1,1)]=string.sub(i,2,2) end--if end--for reset_measure_accidentals() end -------------------------------------- -- function position_as_number -------------------------------------- local function position_as_number (p_pos_as_table) lv_tempstring = tostring(p_pos_as_table) -- strip non numeric characters at the end (notehead info) while ( string.byte(string.sub(lv_tempstring,-1 )) < 48 or string.byte(string.sub(lv_tempstring,-1 )) > 57 ) do lv_tempstring = string.sub(lv_tempstring,1,string.len(lv_tempstring)-1 ) ; end--while lv_accidental = string.sub(lv_tempstring,1,1) lv_position = 0 if lv_accidental == 'v' or lv_accidental == 'b' or lv_accidental == 'n' or lv_accidental == '#' or lv_accidental == 'x' then lv_position = string.sub(lv_tempstring,2) ; else lv_position = lv_tempstring ; lv_accidental = 'z' ; end--if lv_midival = midicalc (lv_position, lv_accidental, gv_transposition) return lv_midival end--function -------------------------------------- -- function modified_item -------------------------------------- local function modified_item (p_item) lv_item = nwcItem.new("|Rest") lv_item:Provide("Dur",p_item.Opts.Dur) lv_item:Provide("Visibility","Never") return lv_item end--function -------------------------------------- -- Main processing ------------------- -------------------------------------- assert(nwcut.getprop('Mode') == nwcut.const.mode_FileText, "Input type must be 'File Text'") assert(nwcut.getprop('ReturnMode') == nwcut.const.mode_FileText, "Under 'Options', check 'Returns File Text'") staff_accidentals = { A="z", B="z", C="z", D="z", E="z", F="z", G="z" }; measure_accidental = { A="z", B="z", C="z", D="z", E="z", F="z", G="z" }; current_clef = nwcItem.new('|Clef|Type:Treble') ; current_instrument = nwcItem.new('|Instrument|Name:"Violin"|Patch:40|Trans:0') ; staff_instrument = nwcItem.new('|StaffInstrument|Name:"Hammond Organ"|Patch:16|Trans:0') ; staff_signature = nwcItem.new('|Key|Signature:C|Tonic:C') ; sigtype = 'staff' ; eval_signature(staff_signature.Opts.Signature) ; measure_signature = nwcItem.new('|Key|Signature:C|Tonic:C') ; sigtype = 'measure' ; eval_signature(measure_signature.Opts.Signature) ; lv_String_NoHit = "|Rest|Dur:" staffitem = 0 gv_transposition = 0 PercussionStaff = {} for i = 1,POSNUMBER,1 do PercussionStaff[i] = {} end--for i for i = 1,POSNUMBER,1 do if i == POSNUMBER then lv_staffname = "Percussion_overflow" else lv_staffname = "Midi_"..i ; end--if lv_item = nwcItem.new("|AddStaff") ; lv_item:Provide("Name",lv_staffname) ; lv_item:Provide("Group","PercussionStaff") ; lv_item:Provide("Label",lv_staffname) ; table.insert (PercussionStaff[i],lv_item) ; lv_item = nwcItem.new("|StaffProperties") ; lv_item:Provide("Color","Default") ; lv_item:Provide("BoundaryTop","10") ; table.insert (PercussionStaff[i],lv_item) ; lv_item = nwcItem.new("|StaffProperties") ; lv_item:Provide("Device","0") ; lv_item:Provide("Channel","10") ; table.insert (PercussionStaff[i],lv_item) ; lv_item = nwcItem.new("|StaffInstrument") ; lv_item:Provide("DynVel","10,30,45,60,75,92,108,127") ; lv_item:Provide("Trans","0") ; table.insert (PercussionStaff[i],lv_item) ; end--for i Flag = {} for item in nwcut.items() do -- do not forget : refresh instrument item & signature to default if item:Is('Editor') then ASI = item.Opts.ActiveStaff + 0 ; end--if if item:Is('AddStaff') then CSI = CSI + 1 ; if CSI == ASI then ASN = CSN ; current_clef = nwcItem.new('|Clef|Type:Treble') ; current_instrument = nwcItem.new('|Instrument|Name:"Violin"|Patch:40|Trans:0') ; staff_instrument = nwcItem.new('|StaffInstrument|Name:"Hammond Organ"|Patch:16|Trans:0') ; staff_signature = nwcItem.new('|Key|Signature:C|Tonic:C') ; sigtype = 'staff' ; eval_signature(staff_signature.Opts.Signature) ; measure_signature = nwcItem.new('|Key|Signature:C|Tonic:C') ; sigtype = 'measure' ; eval_signature(measure_signature.Opts.Signature) ; end--if end--if if item:Is('StaffInstrument') then staff_instrument = item ; end--if if item:Is('Instrument') then current_instrument = item ; end--if if item:Is('Clef') then current_clef = item ; end--if if item:Is('Key') then current_signature = item ; eval_signature(current_signature.Opts.Signature) ; end--if if item:Is('Bar') then reset_measure_accidentals() ; end--if if CSI == ASI then -- define middle note for clef -- |Clef|Type:Treble |Clef|Type:Bass |Clef|Type:Alto |Clef|Type:Tenor |Clef|Type:Treble|OctaveShift:Octave Up |Clef|Type:Treble|OctaveShift:Octave Down |Clef|Type:Percussion -- unless specified, the default type is always initialised to 'Treble' if current_clef.Opts.Type == 'Treble' then lv_relativeposition = 4*7 + 6 ; end--if if current_clef.Opts.Type == 'Alto' then lv_relativeposition = 4*7 + 0 ; end--if if current_clef.Opts.Type == 'Tenor' then lv_relativeposition = 3*7 + 5 ; end--if if current_clef.Opts.Type == 'Bass' then lv_relativeposition = 3*7 + 1 ; end--if if current_clef.Opts.Type == 'Percussion' then lv_relativeposition = 3*7 + 1 ; end--if -- define octaveshift if current_clef.Opts.OctaveShift == 'Octave Down' then lv_relativeposition = lv_relativeposition - 7 ; end--if if current_clef.Opts.OctaveShift == 'Octave Up' then lv_relativeposition = lv_relativeposition + 7 ; end--if -- define transposition gv_transposition = decode_transposition () -- only duration items can be notes if item:HasDuration() then -- reset positions for i=1,POSNUMBER,1 do Flag[i]=0 ; end--for i -- iterate all positions for pos in item:AllNotePositions() do lv_position = position_as_number(pos) lv_midi = decode_note (strip_tie(tostring(pos))) if lv_midi > 0 and lv_midi < POSNUMBER then Flag[lv_midi] = 1 else Flag[POSNUMBER] = 1 end--if end--for pos for i = 1,POSNUMBER,1 do if Flag[i] == 1 then table.insert (PercussionStaff[i],item) else table.insert (PercussionStaff[i],modified_item(item)) ; end--if end--for i else for i=1,POSNUMBER,1 do if (not (item:Is("AddStaff")) and not (item:Is("StaffProperties")) and not (item:Is("StaffInstrument")) ) then table.insert (PercussionStaff[i],item) end ; end--for i end--if end--if print(item) end--for item for j=1,POSNUMBER,1 do counter = 0 for i=1,#PercussionStaff[j] do if (PercussionStaff[j][i]:Is('Note') or PercussionStaff[j][i]:Is('Chord') or PercussionStaff[j][i]:Is('RestChord')) then counter = counter + 1 end ; end--for i for i=1,#PercussionStaff[j] do if counter > 0 then print (PercussionStaff[j][i]) end ; end--for i end--for j