Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathcue_notes_create.lua
More file actions
Latest commit
712 lines (662 loc) · 28.3 KB
/
Copy pathcue_notes_create.lua
File metadata and controls
712 lines (662 loc) · 28.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
functionplugindef()
finaleplugin.RequireSelection=true
finaleplugin.Author="Carl Vine with additional coding by Aaron Sherber"
finaleplugin.AuthorURL="http://carlvine.com/lua/"
finaleplugin.Copyright="https://creativecommons.org/licenses/by/4.0/"
finaleplugin.Version="v0.92i"
finaleplugin.Date="2023/12/25"
finaleplugin.AdditionalMenuOptions=[[
Cue Notes Flip Frozen
]]
finaleplugin.AdditionalUndoText=[[
Cue Notes Flip Frozen
]]
finaleplugin.AdditionalPrefixes=[[
action = "flip"
]]
finaleplugin.MinJWLuaVersion=0.62
finaleplugin.Notes=[[
This script is designed to take music from one staff and create
"cue note" copies in the same measure on one or more empty staves.
The copy is smaller and muted, and can include chosen markings from the original.
It is copied to the chosen layer with a whole-note rest placed in the original layer.
Preferences are preserved between each run.
This script uses an expression category called "Cue Names" which
will be created if needed.
An extra menu, "Cue Notes Flip Frozen", will look for notes in the
previously selected "cue note" layer and flip the direction of their
stems if they have been "frozen" up or down.
]]
return"Cue Notes Create...", "Cue Notes Create", "Copy as cue notes to another staff"
end
action=actionor""
localinfo_notes=[[
This script is designed to take music from one staff and create
"cue note" copies in the same measure on one or more empty staves.
The copy is smaller and muted, and can include chosen markings from the original.
It is copied to the chosen layer with a whole-note rest placed in the original layer.
**
Preferences are preserved between each run.
This script uses an expression category called "Cue Names" which
will be created if needed.
**
An extra menu, "Cue Notes Flip Frozen", will look for notes in the
previously selected "cue note" layer and flip the direction of their
stems if they have been "frozen" up or down.
**
== Command Keys ==
*In the "Destination Staff" window,
hit the tab key to move the cursor into a numeric
field and these key commands are available:
*q @t show these script notes
*w @t flip [copy articulations]
*e @t flip [copy expressions]
*r @t flip [copy smartshapes]
*t @t flip [copy slurs]
*y @t flip [copy clef]
*u @t flip [copy lyrics]
*i @t flip [copy chords]
*o @t flip [mute cuenotes]
*– – –
*a @t all options checked
*s @t no options checked
*d @t select all staves
*f @t select no staves
*g @t select empty staves
*– – –
*z @t next stem direction
*x @t previous stem direction
]]
info_notes=info_notes:gsub("\n%s*", ""):gsub("*", "\n"):gsub("@t", "\t")
localconfig= { -- retained and over-written by the user's "settings" file
copy_articulations=false,
copy_expressions=false,
copy_smartshapes=false,
copy_slurs=true,
copy_clef=false,
copy_lyrics=false,
copy_chords=false,
mute_cuenotes=true,
cuenote_percent=70, -- (75% too big, 66% too small)
source_layer=1, -- layer the cue comes from
cuenote_layer=3, -- layer the cue ends up
rest_layer=1, -- layer for default wholenote rest
freeze_up_down=0, -- "0" for no stem freezing, "1" for up, "2" for down, "3" for away from middle
cuename_item=0, -- ItemNo of the last selected cue_name expression
-- if creating a new "Cue Names" category ...
cue_category_name="Cue Names",
cue_font_smaller=1, -- how many points smaller than the standard technique expression
window_pos_x=false,
window_pos_y=false,
abbreviate=false
}
localoption= {
check= { "copy_articulations", "copy_expressions", "copy_smartshapes",
"copy_slurs", "copy_clef", "copy_lyrics", "copy_chords", "mute_cuenotes" },
integer= { "cuenote_percent", "source_layer", "cuenote_layer" },
stem= { "normal", "freeze up", "freeze down", "away from middle" },
button= { "Set All", "Clear All", "All Staves", "No Staves", "Empty Staves" }
}
localfreeze= {
none=0,
up=1,
down=2,
away_from_middle=3
}
localconfiguration=require("library.configuration")
localclef=require("library.clef")
locallayer=require("library.layer")
localmixin=require("library.mixin")
localscript_name="cue_notes_create"
configuration.get_user_settings(script_name, config, true)
functionshow_error(error_code)
localerrors= {
only_one_staff="Please select just one staff \nas the source for the new cue",
empty_region="Please select a region \nwith some notes in it!",
no_notes_in_source_layer="The selected music contains\nno notes in layer " ..config.source_layer,
first_make_expression_category="You must first create a new Text Expression Category called \""..config.cue_category_name.."\" containing at least one entry",
no_cue_notes="The selected music contains \nno cue notes in layer " ..config.cuenote_layer,
unknown="Unknown error condition"
}
localmsg=errors[error_code] orerrors.unknown
finenv.UI():AlertInfo(msg, "User Error")
return-1
end
functiondont_overwrite_existing_music(staff_number)
localstaff=finale.FCStaff()
staff:Load(staff_number) -- staff number of this slot
localmsg="Overwrite existing music on staff: " ..staff:CreateDisplayFullNameString().LuaString.."?"
localalert=finenv.UI():AlertOkCancel(msg, nil)
return (alert~=finale.OKRETURN)
end
functionregion_is_empty(region, layer_number)
forentryineachentry(region, layer_number) do
ifentry.Count>0thenreturnfalseend
end
returntrue
end
functiondialog_set_position(dialog)
ifconfig.window_pos_xandconfig.window_pos_ythen
dialog:StorePosition()
dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y)
dialog:RestorePosition()
end
end
functiondialog_save_position(dialog)
dialog:StorePosition()
config.window_pos_x=dialog.StoredX
config.window_pos_y=dialog.StoredY
configuration.save_user_settings(script_name, config)
end
localfunctioninfo_dialog()
finenv.UI():AlertInfo(info_notes, "About " ..plugindef())
end
localfunctionmake_info_button(dialog, x, y)
dialog:CreateButton(x, y):SetText("?"):SetWidth(20)
:AddHandleCommand(function() info_dialog() end)
end
functionnew_cue_name(source_staff)
localdialog=mixin.FCXCustomLuaWindow():SetTitle(plugindef())
dialog:CreateStatic(0, 0):SetText("New cue name:"):SetWidth(100)
make_info_button(dialog, 180, 0)
localstaff=finale.FCStaff() -- copy the source Staff Name
staff:Load(source_staff)
localname= {
full=staff:CreateDisplayFullNameString(),
abbrev=staff:CreateDisplayAbbreviatedNameString()
}
localthe_name=dialog:CreateEdit(0, 22):SetWidth(200)
:SetText(config.abbreviateandname.abbrevorname.full)
localabbrev_checkbox=dialog:CreateCheckbox(0, 47):SetText("Abbreviate staff name")
:SetWidth(150):SetCheck(config.abbreviateand1or0)
:AddHandleCommand(function(self)
the_name:SetText(self:GetCheck() ==1andname.abbrevorname.full)
end)
dialog:CreateOkButton()
dialog:CreateCancelButton()
dialog_set_position(dialog)
dialog:RegisterHandleOkButtonPressed(function()
config.abbreviate= (abbrev_checkbox:GetCheck() ==1)
end)
dialog:RegisterInitWindow(function() the_name:SetFocus() end)
dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end)
return (dialog:ExecuteModal(nil) ==finale.EXECMODAL_OK), the_name:GetText()
end
functionchoose_name_index(name_list)
localdialog=mixin.FCXCustomLuaWindow():SetTitle(plugindef())
dialog:CreateStatic(0, 0):SetText("Select cue name:"):SetWidth(100)
-- menu item [0] is "*** new name ***"
localstaff_list=dialog:CreateListBox(0, 22):SetWidth(200):AddString("*** new name ***")
fori, vinipairs(name_list) do-- add all names in the extant list
staff_list:AddString(v[1])
ifv[2] ==config.cuename_itemthenstaff_list:SetSelectedItem(i) end
end
make_info_button(dialog, 180, 0)
dialog:CreateOkButton()
dialog:CreateCancelButton()
dialog_set_position(dialog)
dialog:RegisterHandleOkButtonPressed(function()
localidx=staff_list:GetSelectedItem()
ifidx~=0then-- existing cuename chosen
config.cuename_item=name_list[idx][2]
end
end)
dialog:RegisterInitWindow(function() staff_list:SetKeyboardFocus() end)
dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end)
return (dialog:ExecuteModal(nil) ==finale.EXECMODAL_OK), staff_list:GetSelectedItem()
end
functioncreate_new_expression(exp_name, category_number)
localcat_def=finale.FCCategoryDef()
cat_def:Load(category_number)
localtfi=cat_def:CreateTextFontInfo()
localstr=finale.FCString()
str.LuaString="^fontTxt"
..tfi:CreateEnigmaString(finale.FCString()).LuaString
..exp_name
localted=mixin.FCMTextExpressionDef()
ted:SaveNewTextBlock(str)
:AssignToCategory(cat_def)
:SetUseCategoryPos(true)
:SetUseCategoryFont(true)
:SaveNew()
config.cuename_item=ted:GetItemNo() -- save new item number
end
functionchoose_destination_staff(source_staff)
localstaff_list= {} -- save number and name of other staves in the score
localrgn=finale.FCMusicRegion()
localmax=layer.max_layers()
rgn:SetCurrentSelection()
rgn:SetFullMeasureStack() -- scan the whole stack
localstaff=finale.FCStaff()
forstaff_numberineachstaff(rgn) do
ifstaff_number~=source_staffthen
staff:Load(staff_number)
localfull_name=staff:CreateDisplayFullNameString().LuaString
table.insert(staff_list, { staff_number, full_name } )
end
end
localanswer, saved, buttons= {}, {}, {}
-- make the dialog
localx_grid= { 210, 310, 370 }
localy_step=19
localy_offset=finenv.UI():IsOnMac() and3or0-- + vertical offset for Mac edit boxes
localdialog=mixin.FCXCustomLuaWindow():SetTitle(plugindef())
dialog:CreateStatic(0, 20):SetText("Select cue name:"):SetWidth(100)
localmax_rows=#option.check+#option.integer+2
localnum_rows= (#staff_list> (max_rows+2)) andmax_rowsor (#staff_list+2)
localdata_list=dialog:CreateDataList(0, 0):SetUseCheckboxes(true)
:SetHeight(num_rows*y_step):AddColumn("Destination Staff(s):", 120)
iffinenv.UI():IsOnMac() then
data_list:UseAlternatingBackgroundRowColors()
end
for_, vinipairs(staff_list) do-- list all staff names
localrow=data_list:CreateRow()
row:GetItemAt(0).LuaString=v[2]
end
localfunctionset_check_state(state)
for_, vinipairs(option.check) do
answer[v]:SetCheck(state)
end
data_list:SetKeyboardFocus()
end
localfunctionset_list_state(state)
fori, vinipairs(staff_list) do
locallist_row=data_list:GetItemAt(i-1)
ifstate>-1then-- "No Staves" = 0 / "All Staves" = 1
list_row.Check= (state==1)
else
rgn.StartStaff=v[1] -- is this staff number empty?
rgn.EndStaff=v[1]
list_row.Check=region_is_empty(rgn, 0)
iflist_row.Checkthen
data_list:SelectLine(i-1) -- update menu list visually
end
end
end
end
localfunctionflip_check(idx)
localctl=answer[option.check[idx]]
ctl:SetCheck((ctl:GetCheck() +1) %2)
end
localfunctionflip_direction(add)
localitem=answer.stem_direction:GetSelectedItem() +add
item= (item<0) and3or (item%4)
answer.stem_direction:SetSelectedItem(item)
end
localfunctionkey_check(name)
localctl=answer[name]
locals=ctl:GetText():lower()
if ( s:find("[^0-9]") or
(name:find("layer") ands:find("[^1-" ..max.."]"))
) then
ifs:find("[q?]") theninfo_dialog()
elseifs:find("w") thenflip_check(1)
elseifs:find("e") thenflip_check(2)
elseifs:find("r") thenflip_check(3)
elseifs:find("t") thenflip_check(4)
elseifs:find("y") thenflip_check(5)
elseifs:find("u") thenflip_check(6)
elseifs:find("i") thenflip_check(7)
elseifs:find("o") thenflip_check(8)
elseifs:find("a") thenset_check_state(1) -- check all
elseifs:find("s") thenset_check_state(0) -- check none
elseifs:find("d") thenset_list_state(1) -- all staves
elseifs:find("f") thenset_list_state(0) -- no staves
elseifs:find("g") thenset_list_state(-1) -- empty staves
elseifs:find("z") thenflip_direction(1) -- up/down stem
elseifs:find("x") thenflip_direction(-1)
end
ctl:SetText(saved[name]):SetKeyboardFocus()
elseifs~="" then
ifname:find("layer") thens=s:sub(-1) -- 1-digit layer numbers
elses=s:sub(1, 3) -- 3-digit percentage
end
ctl:SetText(s)
saved[name] =s
end
end
localy=y_step
dialog:CreateStatic(x_grid[1], 0):SetText("Cue Options:"):SetWidth(150)
for_, vinipairs(option.check) do-- run through config boolean list
answer[v] =dialog:CreateCheckbox(x_grid[1], y):SetText(v:gsub("_", ""))
:SetWidth(120):SetCheck(config[v] and1or0)
y=y+y_step
end
fori, vinipairs(option.integer) do-- run through config integer list
dialog:CreateStatic(x_grid[1], y):SetText(v:gsub("_", "") ..":"):SetWidth(150)
answer[v] =dialog:CreateEdit(x_grid[2], y-y_offset):SetInteger(config[v])
:AddHandleCommand(function() key_check(v) end)
answer[v]:SetWidth(i==1and40or20) -- layer numbers thinner
saved[v] =config[v]
y=y+y_step
end
answer.stem_direction=dialog:CreatePopup(x_grid[1], y+5):SetWidth(160)
for_, vinipairs(option.stem) do
answer.stem_direction:AddString("Stems: " ..v)
end
answer.stem_direction:SetSelectedItem(config.freeze_up_down) -- 0-based index configure value
-- buttons to PRESET checkboxes/data_list items
fori, nameinipairs(option.button) do
buttons[name] =dialog:CreateButton(x_grid[3], y_step*2* (i-1)):SetWidth(80):SetText(name)
ifi<3then
buttons[name]:AddHandleCommand(function() set_check_state(2-i) end)
else
buttons[name]:AddHandleCommand(function() set_list_state(4-i) end)
end
end
make_info_button(dialog, x_grid[3] +60, y_step*11+3)
-- run the dialog
dialog:CreateOkButton()
dialog:CreateCancelButton()
dialog_set_position(dialog)
localchosen_staves= {} -- save user choice of destination staves
dialog:RegisterHandleOkButtonPressed(function()
localselection=data_list:GetSelectedLine() +1
ifselection>0then-- user selected a line (not necessairly the line's checkbox)
table.insert(chosen_staves, staff_list[selection][1])
end
fori, vinipairs(staff_list) do-- check every staff for ticked boxes
locallist_row=data_list:GetItemAt(i-1)
iflist_row.Checkandi~=selectionthen
table.insert(chosen_staves, v[1])
end
end
-- save config values
for_, vinipairs(option.check) do
config[v] = (answer[v]:GetCheck() ==1)
end
for_, vinipairs(option.integer) do
config[v] =answer[v]:GetInteger()
end
ifconfig.source_layer~=config.cuenote_layerthen
config.rest_layer=config.source_layer
else-- make sure the whole-bar rest is in a different layer from the cuenotes
config.rest_layer= (config.source_layer%max) +1
end
config.freeze_up_down=answer.stem_direction:GetSelectedItem() -- 0-based index
end)
dialog:RegisterInitWindow(function() data_list:SetKeyboardFocus() end)
dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end)
return (dialog:ExecuteModal(nil) ==finale.EXECMODAL_OK), chosen_staves
end
functionfix_text_expressions(region)
localexpressions=finale.FCExpressions()
expressions:LoadAllForRegion(region)
forexpressionineachbackwards(expressions) do
ifexpression.StaffGroupID==0then-- note-attached expressions only
ifconfig.copy_expressionsthen-- keep them and switch to cuenote layer
expression.LayerAssignment=config.cuenote_layer
expression.ScaleWithEntry=true-- and scale to smaller noteheads
expression:Save()
else
expression:DeleteData() -- otherwise delete them
end
end
end
end
functionget_away_from_middle_is_up(region)
ifconfig.freeze_up_down~=freeze.away_from_middlethenreturnfalseend
localtotal_displacement=0
forentryineachentry(region) do
ifentry:IsNote() then
fornoteineach(entry) do
total_displacement=total_displacement+ (note:CalcStaffPosition() +4)
end
end
end
returntotal_displacement>=0
end
functionfreeze_tuplets_and_ties(entry, up)
ifentry:IsNote() andentry:IsTied() then
fornoteineach(entry) do
ifnote.Tiethen
localtie_mod=finale.FCTieMod(finale.TIEMODTYPE_TIESTART)
tie_mod.TieDirection=upandfinale.TIEMODDIR_OVERorfinale.TIEMODDIR_UNDER
tie_mod:SaveAt(note)
end
end
end
ifentry.TupletStartFlagthen
fortupletineach(entry:CreateTuplets()) do
tuplet.PlacementMode=finale.TUPLETPLACEMENT_STEMSIDE
tuplet:Save()
end
end
end
functionfreeze_slurs(region, up)
localmarks=finale.FCSmartShapeMeasureMarks()
marks:LoadAllForRegion(region, true)
formineach(marks) do
localshape=m:CreateSmartShape()
ifshape:IsSolidSlur() then
shape:SetShapeType(upandfinale.SMARTSHAPE_SLURUPorfinale.SMARTSHAPE_SLURDOWN)
shape:Save()
elseifshape:IsDashedSlur() then
shape:SetShapeType(upandfinale.SMARTSHAPE_DASHEDSLURUPorfinale.SMARTSHAPE_DASHEDSLURDOWN)
shape:Save()
end
end
end
functioncopy_to_destination(source_region, destination_staff)
localdestination_region=mixin.FCMMusicRegion()
destination_region:SetRegion(source_region):CopyMusic() -- copy the original
destination_region:SetStartStaff(destination_staff):SetEndStaff(destination_staff)
ifnotregion_is_empty(destination_region, 0)
anddont_overwrite_existing_music(destination_staff) then
destination_region:ReleaseMusic() -- clear memory
returnfalse-- and go home
elseifregion_is_empty(source_region, config.source_layer) then
destination_region:ReleaseMusic() -- clear memory
show_error("no_notes_in_source_layer")
returnfalse-- and go home
end
-- otherwise carry on ...
destination_region:PasteMusic() -- paste the copy
destination_region:ReleaseMusic() -- and release memory
forlayer_number=1, layer.max_layers() do-- clear out non-source layers
iflayer_number~=config.source_layerthen
layer.clear(destination_region, layer_number)
end
end
-- swap source_layer with cuenote_layer & fix clef
layer.swap(destination_region, config.source_layer, config.cuenote_layer)
ifnotconfig.copy_clefthen
clef.restore_default_clef(destination_region.StartMeasure, destination_region.EndMeasure, destination_staff)
end
localaway_from_middle_is_up=get_away_from_middle_is_up(destination_region)
-- mute / set to % size / delete articulations? / freeze stems? / delete lyrics?
forentryineachentrysaved(destination_region) do
ifentry:IsNote() andconfig.mute_cuenotesthen
entry.Playback=false
end
entry:SetNoteDetailFlag(true)
mixin.FCMEntryAlterMod()
:SetNoteEntry(entry)
:SetResize(config.cuenote_percent)
:Save()
ifentry.ArticulationFlagandnotconfig.copy_articulationsthen
forarticulationineach(entry:CreateArticulations()) do
articulation:DeleteData()
end
entry.ArticulationFlag=false
end
ifentry.LyricFlagandnotconfig.copy_lyricsthen-- delete lyrics from copy
locallyrics= { finale.FCChorusSyllable(), finale.FCSectionSyllable(), finale.FCVerseSyllable() }
for_, vinipairs(lyrics) do
v:SetNoteEntry(entry)
whilev:LoadFirst() do
v:DeleteData()
end
end
end
ifconfig.freeze_up_down>freeze.nonethen-- frozen stems requested
entry.FreezeStem=true
localfreeze_stem_up= {
true,
false,
away_from_middle_is_up
}
entry.StemUp=freeze_stem_up[config.freeze_up_down]
else
entry.FreezeStem=false
end
-- freeze ties and tuplets for "away from middle" stems
ifconfig.freeze_up_down==freeze.away_from_middlethen
freeze_tuplets_and_ties(entry, away_from_middle_is_up)
end
end
-- delete or amend text expressions
fix_text_expressions(destination_region)
-- check smart shapes
ifnotconfig.copy_smartshapesornotconfig.copy_slursthen
formarkinloadallforregion(finale.FCSmartShapeMeasureMarks(), destination_region) do
localshape=mark:CreateSmartShape()
if (shape:IsSlur() andnotconfig.copy_slurs) or
(notshape:IsSlur() andnotconfig.copy_smartshapes) then
shape:DeleteData()
end
end
end
ifconfig.copy_slursandconfig.freeze_up_down==freeze.away_from_middlethen
freeze_slurs(destination_region, away_from_middle_is_up)
end
-- delete chord symbols?
ifnotconfig.copy_chordsthen
forchordinloadallforregion(finale.FCChords(), destination_region) do
ifchordthenchord:DeleteData() end
end
end
-- create whole-note rest in rest_layer in each measure
formeasure=destination_region.StartMeasure, destination_region.EndMeasuredo
localnotecell=finale.FCNoteEntryCell(measure, destination_staff)
notecell:Load()
localwhole_note=notecell:AppendEntriesInLayer(config.rest_layer, 1) -- Append to rest_layer, add 1 entry
ifwhole_notethen
whole_note.Duration=finale.WHOLE_NOTE
whole_note.Legality=true
whole_note:MakeRest()
notecell:Save()
end
end
returntrue
end
functionnew_expression_category(new_name)
localcategory_id=0
ifnotfinenv.IsRGPLuathen-- SaveNewWithType only works on RGPLua 0.58+
returnfalse, category_id-- and crashes on JWLua
end
localnew_category=mixin.FCMCategoryDef()
new_category:Load(finale.DEFAULTCATID_TECHNIQUETEXT)
localstr=finale.FCString()
str.LuaString=new_name
new_category:SetName(str)
:SetVerticalAlignmentPoint(finale.ALIGNVERT_STAFF_REFERENCE_LINE)
:SetVerticalBaselineOffset(30)
:SetHorizontalAlignmentPoint(finale.ALIGNHORIZ_CLICKPOS)
:SetHorizontalOffset(-18)
-- make font slightly smaller than standard TECHNIQUE expression
localtfi=new_category:CreateTextFontInfo()
tfi.Size=tfi.Size-config.cue_font_smaller
new_category:SetTextFontInfo(tfi)
localok=new_category:SaveNewWithType(finale.DEFAULTCATID_TECHNIQUETEXT)
ifokthen
category_id=new_category:GetID()
end
returnok, category_id
end
functioncreate_cue_notes()
localcue_names= { } -- compile NAME/ItemNo of all pre-existing CUE_NAME expressions
localsource_region=finenv.Region()
localstart_staff=source_region.StartStaff
-- declare other local variables
localok, name_index, new_expression, destination_staves
ifsource_region:CalcStaffSpan() >1then
returnshow_error("only_one_staff")
elseifregion_is_empty(source_region, 0) then
returnshow_error("empty_region")
end
localcat_ID=-1-- assume the CUE_NAMES category doesn't exist
localcat_defs=finale.FCCategoryDefs()
cat_defs:LoadAll()
forcatineach(cat_defs) do
ifcat:CreateName().LuaString==config.cue_category_namethen
cat_ID=cat.ID
break
end
end
localexpression_defs=finale.FCTextExpressionDefs()
expression_defs:LoadAll()
ifcat_ID>-1then-- expression category already exists
fortext_defineach(expression_defs) do-- collate existing cue names
iftext_def.CategoryID==cat_IDthen
localstr=text_def:CreateTextString()
str:TrimEnigmaTags()
table.insert(cue_names, { str.LuaString, text_def.ItemNo } ) -- save expresion NAME and ItemNo
end
end
table.sort(cue_names, function(a, b) returnstring.lower(a[1]) <string.lower(b[1]) end)
end
-- test for pre-existing names
ifcat_ID<0then-- create a new Text Expression Category
ok, cat_ID=new_expression_category(config.cue_category_name)
ifnotokthen-- creation failed
returnshow_error("first_make_expression_category")
end
end
-- choose cue name
ok, name_index=choose_name_index(cue_names) -- saved in config.cuename_item
ifnotokthenreturnend
ifname_index==0then-- USER wants to provide a new cue name
ok, new_expression=new_cue_name(start_staff)
ifnotokornew_expression=="" thenreturnend
create_new_expression(new_expression, cat_ID) -- ID saved in config.cuename_item
end
-- choose destination staff
ok, destination_staves=choose_destination_staff(start_staff)
ifnotokthenreturnend
ifregion_is_empty(source_region, config.source_layer) then
returnshow_error("no_notes_in_source_layer")
end
-- make the cue copy
for_, one_staffinipairs(destination_staves) do
ifcopy_to_destination(source_region, one_staff) then
mixin.FCMExpression() -- "name" the cue
:SetStaff(one_staff)
:SetVisible(true)
:SetMeasurePos(0)
:SetScaleWithEntry(false) -- could also (possibly) be true!
:SetPartAssignment(true)
:SetScoreAssignment(true)
:SetID(config.cuename_item)
:SaveNewToCell(finale.FCCell(source_region.StartMeasure, one_staff))
end
end
source_region:SetInDocument()
end
functionflip_cue_notes()
localregion=finenv.Region()
ifregion_is_empty(region, config.cuenote_layer) then
show_error("no_cue_notes")
return
end
forstaff=region.StartStaff, region.EndStaffdo
localfreeze_up=nil
localstaff_region=mixin.FCMMusicRegion()
:SetRegion(region)
:SetStartStaff(staff)
:SetEndStaff(staff)
forentryineachentrysaved(staff_region, config.cuenote_layer) do
ifentry:IsNote() andnotentry.FreezeStemthengotonext_staffend
entry.StemUp=notentry.StemUp
iffreeze_up==nilthenfreeze_up=entry.StemUpend
freeze_tuplets_and_ties(entry, freeze_up)
end
freeze_slurs(staff_region, freeze_up)
::next_staff::
end
end
ifaction=="flip" then
flip_cue_notes()
else
create_cue_notes()
end