0
# Advanced Features
1
2
This document covers advanced functionality including experimental editor features, layout manipulation, locale management, runtime measurement, and other specialized capabilities.
3
4
## Capabilities
5
6
### Experimental Editor Functions
7
8
Experimental editing capabilities for modifying loaded MEI documents.
9
10
**Warning**: These functions are experimental and should not be relied upon for production use. The API may change in future versions.
11
12
```python { .api }
13
class toolkit:
14
def edit(self, editor_action: dict) -> bool:
15
"""
16
Edit the MEI data (experimental).
17
18
This is experimental code not to rely on. The API and
19
behavior may change in future versions.
20
21
Args:
22
editor_action: Dictionary with editor action specifications
23
24
Returns:
25
True if edit action was successfully applied, False otherwise
26
"""
27
28
def editInfo(self) -> dict:
29
"""
30
Get editor status (experimental).
31
32
This is experimental code not to rely on. Returns information
33
about the current editor state.
34
35
Returns:
36
Dictionary with editor status information
37
"""
38
```
39
40
### Layout Manipulation
41
42
Redo layout calculations with updated options or after modifications.
43
44
```python { .api }
45
class toolkit:
46
def redoLayout(self, options: dict | None = None) -> None:
47
"""
48
Redo the layout of the loaded data.
49
50
Call this after changing rendering options (e.g., page size,
51
zoom level) to recalculate the layout without reloading data.
52
53
Args:
54
options: Dictionary with action options:
55
- resetCache: bool, true to reset cache (default: True)
56
"""
57
58
def redoPagePitchPosLayout(self) -> None:
59
"""
60
Redo pitch position layout for the current page.
61
62
Only recalculates vertical positions of notes. For full
63
recalculation, use redoLayout() instead.
64
"""
65
```
66
67
### Locale Management
68
69
Control locale settings for the toolkit instance.
70
71
```python { .api }
72
class toolkit:
73
def setLocale(self) -> None:
74
"""
75
Set the global locale for the toolkit instance.
76
"""
77
78
def resetLocale(self) -> None:
79
"""
80
Reset the global locale to the previous value.
81
"""
82
```
83
84
### Runtime Measurement
85
86
Measure and log execution time for performance analysis.
87
88
```python { .api }
89
class toolkit:
90
def initClock(self) -> None:
91
"""
92
Initialize the runtime clock.
93
94
Start timing for performance measurement.
95
"""
96
97
def resetClock(self) -> None:
98
"""
99
Reset the runtime clock.
100
101
Reset timing measurements to zero.
102
"""
103
104
def getRuntimeInSeconds(self) -> float:
105
"""
106
Get the elapsed runtime in seconds.
107
108
Returns:
109
Runtime in seconds as float
110
"""
111
112
def logRuntime(self) -> None:
113
"""
114
Log runtime information.
115
116
Write runtime information to the log.
117
"""
118
```
119
120
## Usage Examples
121
122
### Performance Measurement
123
124
```python
125
import verovio
126
127
tk = verovio.toolkit()
128
129
# Initialize timing
130
tk.initClock()
131
132
# Load and render
133
tk.loadFile("large_score.mei")
134
page_count = tk.getPageCount()
135
136
for page in range(1, page_count + 1):
137
svg = tk.renderToSVG(pageNo=page)
138
139
# Get elapsed time
140
elapsed = tk.getRuntimeInSeconds()
141
print(f"Rendered {page_count} pages in {elapsed:.2f} seconds")
142
print(f"Average: {elapsed/page_count:.3f} seconds per page")
143
144
# Log to Verovio's internal log
145
tk.logRuntime()
146
```
147
148
### Benchmarking Different Options
149
150
```python
151
import verovio
152
153
def benchmark_rendering(filename, options_list):
154
"""Benchmark rendering with different option sets."""
155
tk = verovio.toolkit()
156
tk.loadFile(filename)
157
158
results = []
159
160
for idx, options in enumerate(options_list):
161
# Reset and start timing
162
tk.resetClock()
163
tk.initClock()
164
165
# Apply options and redo layout
166
tk.setOptions(options)
167
tk.redoLayout()
168
169
# Render all pages
170
page_count = tk.getPageCount()
171
for page in range(1, page_count + 1):
172
svg = tk.renderToSVG(pageNo=page)
173
174
# Record time
175
elapsed = tk.getRuntimeInSeconds()
176
results.append({
177
'options': options,
178
'time': elapsed,
179
'pages': page_count
180
})
181
182
print(f"Config {idx+1}: {elapsed:.2f}s for {page_count} pages")
183
184
return results
185
186
# Test different scales
187
options_to_test = [
188
{'scale': 40},
189
{'scale': 60},
190
{'scale': 80},
191
{'scale': 100}
192
]
193
194
results = benchmark_rendering("score.mei", options_to_test)
195
```
196
197
### Dynamic Layout Adjustments
198
199
```python
200
import verovio
201
202
tk = verovio.toolkit()
203
tk.loadFile("score.mei")
204
205
# Initial render
206
initial_options = {
207
'pageHeight': 2970,
208
'pageWidth': 2100,
209
'scale': 40
210
}
211
tk.setOptions(initial_options)
212
svg1 = tk.renderToSVG()
213
214
# Change options and redo layout
215
new_options = {
216
'pageHeight': 3960,
217
'pageWidth': 2800,
218
'scale': 60
219
}
220
tk.setOptions(new_options)
221
tk.redoLayout()
222
223
# Render with new layout
224
svg2 = tk.renderToSVG()
225
print(f"Pages after resize: {tk.getPageCount()}")
226
```
227
228
### Incremental Layout Updates
229
230
```python
231
import verovio
232
233
tk = verovio.toolkit()
234
tk.loadFile("score.mei")
235
236
# Full layout
237
tk.redoLayout()
238
svg = tk.renderToSVG(pageNo=1)
239
240
# Make a small pitch adjustment (if needed)
241
# Then do quick pitch position recalculation
242
tk.redoPagePitchPosLayout()
243
244
# Render updated page
245
svg_updated = tk.renderToSVG(pageNo=1)
246
```
247
248
### Responsive Score Viewer
249
250
```python
251
import verovio
252
253
class ResponsiveScoreViewer:
254
def __init__(self, filename):
255
self.tk = verovio.toolkit()
256
self.tk.loadFile(filename)
257
self.current_page = 1
258
259
def resize_viewport(self, width, height):
260
"""Adjust score layout for new viewport size."""
261
self.tk.resetClock()
262
self.tk.initClock()
263
264
# Update page dimensions
265
options = {
266
'pageWidth': width,
267
'pageHeight': height,
268
'adjustPageHeight': True
269
}
270
self.tk.setOptions(options)
271
272
# Redo layout
273
self.tk.redoLayout()
274
275
elapsed = self.tk.getRuntimeInSeconds()
276
print(f"Layout recalculated in {elapsed:.3f}s")
277
278
return self.tk.getPageCount()
279
280
def set_zoom(self, scale):
281
"""Change zoom level."""
282
self.tk.setScale(scale)
283
self.tk.redoLayout()
284
285
def render_current_page(self):
286
"""Render the current page."""
287
return self.tk.renderToSVG(pageNo=self.current_page)
288
289
# Usage
290
viewer = ResponsiveScoreViewer("score.mei")
291
292
# Simulate window resize
293
new_page_count = viewer.resize_viewport(2400, 3200)
294
print(f"Document now has {new_page_count} pages")
295
296
# Change zoom
297
viewer.set_zoom(60)
298
299
# Render
300
svg = viewer.render_current_page()
301
```
302
303
### Layout Optimization
304
305
```python
306
import verovio
307
308
def find_optimal_scale(filename, target_pages):
309
"""Find scale that produces target number of pages."""
310
tk = verovio.toolkit()
311
tk.loadFile(filename)
312
313
# Binary search for optimal scale
314
min_scale = 10
315
max_scale = 150
316
tolerance = 2 # pages
317
318
while max_scale - min_scale > 5:
319
test_scale = (min_scale + max_scale) // 2
320
321
tk.setScale(test_scale)
322
tk.redoLayout()
323
pages = tk.getPageCount()
324
325
print(f"Scale {test_scale}: {pages} pages")
326
327
if abs(pages - target_pages) <= tolerance:
328
print(f"Found optimal scale: {test_scale} ({pages} pages)")
329
return test_scale
330
331
if pages > target_pages:
332
# Need larger scale to fit more on each page
333
min_scale = test_scale
334
else:
335
# Need smaller scale
336
max_scale = test_scale
337
338
final_scale = (min_scale + max_scale) // 2
339
tk.setScale(final_scale)
340
tk.redoLayout()
341
print(f"Best scale: {final_scale} ({tk.getPageCount()} pages)")
342
return final_scale
343
344
# Find scale for ~10 pages
345
optimal = find_optimal_scale("score.mei", target_pages=10)
346
```
347
348
### Locale-Aware Processing
349
350
```python
351
import verovio
352
353
tk = verovio.toolkit()
354
355
# Set locale for proper text rendering
356
tk.setLocale()
357
358
# Load and process
359
tk.loadFile("score_with_text.mei")
360
svg = tk.renderToSVG()
361
362
# Reset locale when done
363
tk.resetLocale()
364
```
365
366
### Performance Profiling Suite
367
368
```python
369
import verovio
370
import statistics
371
372
class PerformanceProfiler:
373
def __init__(self):
374
self.tk = verovio.toolkit()
375
self.measurements = []
376
377
def profile_operation(self, operation_name, operation_func):
378
"""Profile a single operation."""
379
self.tk.resetClock()
380
self.tk.initClock()
381
382
result = operation_func()
383
384
elapsed = self.tk.getRuntimeInSeconds()
385
self.measurements.append({
386
'operation': operation_name,
387
'time': elapsed
388
})
389
390
print(f"{operation_name}: {elapsed:.4f}s")
391
return result
392
393
def profile_file(self, filename):
394
"""Profile all major operations on a file."""
395
print(f"\nProfiling: {filename}")
396
397
# Load
398
self.profile_operation(
399
"Load",
400
lambda: self.tk.loadFile(filename)
401
)
402
403
# Get page count
404
page_count = self.profile_operation(
405
"Get page count",
406
lambda: self.tk.getPageCount()
407
)
408
409
# Render SVG
410
self.profile_operation(
411
"Render to SVG",
412
lambda: self.tk.renderToSVG()
413
)
414
415
# Render MIDI
416
self.profile_operation(
417
"Render to MIDI",
418
lambda: self.tk.renderToMIDI()
419
)
420
421
# Get MEI
422
self.profile_operation(
423
"Export MEI",
424
lambda: self.tk.getMEI()
425
)
426
427
# Generate timemap
428
self.profile_operation(
429
"Generate timemap",
430
lambda: self.tk.renderToTimemap()
431
)
432
433
def print_summary(self):
434
"""Print performance summary."""
435
print("\n=== Performance Summary ===")
436
total_time = sum(m['time'] for m in self.measurements)
437
print(f"Total time: {total_time:.4f}s")
438
439
times = [m['time'] for m in self.measurements]
440
print(f"Mean operation time: {statistics.mean(times):.4f}s")
441
print(f"Median operation time: {statistics.median(times):.4f}s")
442
443
print("\nSlowest operations:")
444
sorted_ops = sorted(self.measurements, key=lambda x: x['time'], reverse=True)
445
for op in sorted_ops[:3]:
446
print(f" {op['operation']}: {op['time']:.4f}s")
447
448
# Usage
449
profiler = PerformanceProfiler()
450
profiler.profile_file("score.mei")
451
profiler.print_summary()
452
```
453
454
### Cache Management
455
456
```python
457
import verovio
458
459
tk = verovio.toolkit()
460
tk.loadFile("score.mei")
461
462
# Initial layout with cache
463
tk.redoLayout()
464
465
# Change options
466
tk.setScale(60)
467
468
# Redo with cache reset (full recalculation)
469
tk.redoLayout(options={'resetCache': True})
470
471
# Redo without cache reset (may use cached data)
472
tk.setScale(80)
473
tk.redoLayout(options={'resetCache': False})
474
```
475
476
### Debug Timing for Operations
477
478
```python
479
import verovio
480
481
def timed_render_pipeline(filename):
482
"""Time each step of the rendering pipeline."""
483
tk = verovio.toolkit()
484
485
# Time loading
486
tk.initClock()
487
tk.loadFile(filename)
488
load_time = tk.getRuntimeInSeconds()
489
print(f"Load time: {load_time:.4f}s")
490
491
# Time layout
492
tk.resetClock()
493
tk.initClock()
494
tk.redoLayout()
495
layout_time = tk.getRuntimeInSeconds()
496
print(f"Layout time: {layout_time:.4f}s")
497
498
# Time first page render
499
tk.resetClock()
500
tk.initClock()
501
svg = tk.renderToSVG(pageNo=1)
502
render_time = tk.getRuntimeInSeconds()
503
print(f"First page render: {render_time:.4f}s")
504
505
# Time MIDI generation
506
tk.resetClock()
507
tk.initClock()
508
midi = tk.renderToMIDI()
509
midi_time = tk.getRuntimeInSeconds()
510
print(f"MIDI generation: {midi_time:.4f}s")
511
512
total = load_time + layout_time + render_time + midi_time
513
print(f"\nTotal pipeline time: {total:.4f}s")
514
515
return {
516
'load': load_time,
517
'layout': layout_time,
518
'render': render_time,
519
'midi': midi_time,
520
'total': total
521
}
522
523
# Profile a file
524
timings = timed_render_pipeline("score.mei")
525
```
526