Review the use of Actions within the whole application, to take advantage of their properties, such as name, Tooltip, etc...\nDone
Be more aggressive for compounds, using even known glyphs (with a bad rating) trying to reach a compound with better rating.\nThis idea has turned out to be very efficient
<<listTags Closed title # >>
<<listTags Info title # >>
This list gathers all items currently tagged as ''Open''. You can also display AllClosedItems.\n<<listTags Open title # >>
When assigning an alteration (sharp, flat, natural), we should look not only to simple note heads, but also to multiple note heads (such as ~BLACK_NOTE_HEAD_2), and check the geometry accordingly
Launching "sement for stems" on glyph 771 in DebuMandSample seems to hang the application\nFixed (was due to endless splitting of beam groups with erroneous beam glyphs)
The user should have the ability to assign a barline shape (of his choice) to a glyph.\nThis is part of a larger rework to make a separation between handling barlines to retrieve systems and handling barlines to retrieve measures. The former should be part of a SYSTEMS step. Doing so, the BARS step would disappear and the barlines would be translated to measures by ScoreBuilder in some TranslateBars. The user would be able to assign and deassign measure barlines at will (within systems) just like any other symbol.\nDone in V3.2
The logic currently in use is to take the first point (left side) of the slur and consider the part of the point to be also the containing part for the slur. This works in most cases, but not in the following example where the first staff is one part, the two other staves are the second part, and the reference point of the slur is closer to staff 1 than to staff 2.\n[img[Top Slur assigned to wrong part|images/slur-part.jpg]] \nA solution would be to take into account the curvature direction of the slur, and more precisely the notes (heads ?, beams ?, stems ?) that are embraced by the slur. Then, simply use their containing part. Here these note heads belong to staff 2, and therefore to part 2.\nAnyway, we need an algorithm to determine the notes which are embraced by a given slur, so let's go this way.
Several information items are used to remember whether a Section or a Glyph is assigned (to some musical entity) or still available for further processing & recognition.\n*A ''Glyph'' instance has :\n**A ''result'', which can be : \n***null\n***success\n***failure\n**A ''shape'', which can be : \n***null\n***known (not null, not //''NOISE''//)\n***wellKnown (not null, not //''~NO_LEGAL_SHAPE''//, not member of Garbage (//''NOISE''// or //''STRUCTURE''//)). This is a subset of the known glyphs.\n*A ''Section'' instance may have a link to a containing Glyph instance :\n**If the link is null, the section is free\n**If the link is not null, then the above rules apply transitively between the Glyph and the Section instances\n\nThe question is to make sure that the rules are consistently applied.\nPerhaps this dual information result / shape could be simplified. To be investigated.
Use ~BeamGroup parameters to forge a common slope for beam painting. The purpose is to come out with a better looking painting of the beams than the current solution based on (rather raw) value of individual beam segments.\nVarious approaches have been tried, including forcing the slope of the longest beam in the group to be used by all beams. The results are not really better, they may even be worse on some occasions.\nSo this topic is closed.
Add a sanity check for beam hook : the mean line must intersect the left & right sides of the contour box
#Creator: Ludwig van Beethoven cannot be flagged as a composer (nyi)\n#M9 & M10: 2 slashed grace notes need to be translated (nyi)\n
#M1: --"sempre dolce" not related to a precise note.-- Fixed by choosing staff above direction statement if such staff exists, otherwise the staff below, and pick up the closest chord.\n#M2 lyrics: how to manually enter the "extension" sign (something like a '_')\n#M6 & 7: --Notes that belong to upper staff are associated with the lower staff (see ledgers) perhaps because the note head center is closer to the lower staff. We should consider the stem.-- Fixed, by using stem information when a note is really far from "its" staff.
This is a tablature, something Audiveris does not handle for the time being.
The idea is to have an easy way to collect all pending defaults, and let the user browse visually through it, to review (and fix) all the remaining spurious items.\nDone via the ErrorsEditor, with ability to navigate to the related glyph or score entity
I have tried to approximate Slurs by Ellipses (see the class omr.math.Ellipse). This works but the computed ellipse if often shrunk too much, missing the slur edges by a significant number of pixels. This is reportedly due to the algebraic distance.\nEven if slurs may be closer to Ellipses that Circles, the computed Circles fit rather well. So, for the time being, I approximate Slurs by Circles, using class omr.math.Circle.
We should augment the current GlyphBoard, so that for a Creator text we would allow the user to enter the type (such as composer, etc)
#M1: "Allegro vivace" direction is said as being with no related note\n#M1, M2, M3: All ARPEGIATTO signs are drawn on a wrong location (obvious bug)\n#M10: A leg of a crescendo sign is mistaken for an ending by HorizontalsBuilder. No way to undo the mistake.\n#M11: Missing key signature. With a flat sign in the middle of nowhere. A bug.
AllOpenItems
#M6 & M7: --Complex measures not correctly handled, as well as many more.-- Fixed: was due to too many chords taken as interleaved chords\n#S3P2: --Cannot left connect 2 stems-- Not reproduced.
Implement @@double beams@@ as recognizable glyphs, in order to cope with connected beams.\nFor the time being, these stuck beams are often mistaken for say a black note head.\nDone for double and triple beam items
When the user selects a few glyphs, the popup menu should immediately build a compound prototype and present its evaluation to the user, who would simply click on the proposal to accept it.\nDone, available both from ~EvaluationBoard and from the Glyph Popup menu
Dynamics handling is implemented (Piano, Forte, etc...)\nBut we need a more comprehensive handling of dynamics, to cope with "sfz", "rf", "sfpp", etc and not just piano or forte combinations.\n*When a name is usual, such as FORTE or ~MEZZO_FORTE, just keep it.\n*For other notations, simply use for example ~DYNAMICS_SFZUse the MusicXML definitions for proper collection of symbols to handle.\nAllow lexical combination when the resulting value is one of the handled dynamics
For the developper, an exception stack trace is certainly very useful to investigate the cause and fix it.\nFor the end user, the stack trace will be experienced as annoying.\nWhy not use the logger.warning(text, ex) method and depending on the value of a constant (such as printStackTraces in Logger class) we print or not the stack trace.\n''Caution'': class Constant uses class Logger, so let's make sure we won't fall into circular elaboration problems while using Constant stuff in the Logger class.\nDone.\nSimilarly, a severe error will exit or not the application based on a constant flag
Export notes to MusicXML file
Slurs need to be properly exported to the ~MusicXML file, using the tie element of Note or the slur and/or tied elements of notation in Note (to be clarified with ~MusicXML DTD's and examples).\nThis is done, slurs and ties are correctly exported, with placement/orientation attributes and bezier data as well.
# Many chords are mistaken for BRACKET. Should add a specific test on staff embraced.\n#M9: tuplet with no beam (just a quarter and an eighth), not handled\n#M?: A chord with two void heads, each with a dot. Ends up with two augmentation dots on one note and one on the other.\n# --Finale complaining about lyric elements.-- Fixed by swapping syllabic and text elements to be compliant with MusicXML definition
Implement the score Fermata element (in the barline domain) from the fermata glyph.\nDone as a Notation
Location of fermata signs cannot rely on slot, because whole notes don't have related slot
Use translated / untranslated (but known) to select glyphs displayed on the sheet view\nSo that remaining glyphs get clearly visible
Without calling into question the power of the NeuralNetwork, experience has shown that some basic sanity checks could be run to avoid obvious mistakes.\nA good example is the number symbols of a time signature : their pitch position must be clearly on the staff, not higher, not lower.\nWhen could we use such checks :\n*Right after the NeuralNetwork evaluations are retrieved for a given glyph, and before the evaluations are reported to the caller, some simplistic checks are already performed.\n*They could also be run in some cleanup phase.
See SectionGlyphAndShape\n+++![SystemInfo]>\n*vSections\n**Fed by BarsBuilder from __all__ vLag sections, and split by system\n**Read by GlyphsBuilder.retrieveSystemGlyphs(). Glyphs are built by aggregation of these sections that are __!isKnown()__\n*glyphs (non-active glyphs are constantly removed from this collection)\n**Fed initially by BarsBuilder calling splitBarSticks (thus only the bar glyphs)\n**Fed incrementally by GlyphsBuilder.insertGlyph (which inserts both into vLag and into system)\n**Pruned incrementally by GlyphsBuilder.removeGlyph(which removes from proper system and destroys in vLag))\n===\n++++![Steps]>\n++++!![BARS]>\n*Use a LagBuilder to create all sections from Picture individual pixels\n*Use a VerticalArea to retrieve sticks candidates out of ''sections'' for which __!section.isKnown()__\n*Late rejected sticks are destroyed (no cutSection) Q: is this useful?\n*Accepted sticks are inserted in proper systems by GlyphsBuilder.insertGlyph\n*All vertical sections are split among the system vSections\n===\n++++!![SYMBOLS]>\n*GlyphsBuilder.retrieveGlyphs builds glyphs by aggregation of system ''sections'' that __!isKnown()__\n*glyphs are inserted by GlyphsBuilder.insertGlyph\n*GlyphInspector.evaluateGlyphs assigns a shape when possible\n===\n++++!![SYMBOLS_COMPOUNDS]>\n*GlyphInspector.retrieveSystemCompounds from system ''active glyphs'' (rather than from sections)\n**With BasicAdapter : __glyph.isActive() && (!glyph.isKnown() || (!glyph.isManualShape() && ((shape == DOT) || (shape == SLUR) || (shape == CLUTTER) || (glyph.getDoubt() >= getMinCompoundPartDoubt()))))__\n*Accepted compounds are inserted by GlyphsBuilder.insertCompound\n===\n++++!![VERTICALS]>\n*GlyphInspector.retrieveAllVerticals loops on each system:\n##GlyphsBuilder.removeSystemInactives (removed from system, sections are not cut)\n##A VerticalsBuilder uses one VerticalArea per system based on a SectionPredicate to filter ''sections'' __glyph==null || !glyph.isWellKnown()__\n##There is one CheckSuite per system, since system is used in certain checks\n##Accepted stems are inserted by GlyphsBuilder.insertGlyph()\n===\n++++!![LEAVES]>\n*GlyphsBuilder.retrieveGlyphs builds glyphs by aggregation of ''sections'' that are __!isKnown()__\n*glyphs are inserted by GlyphsBuilder.insertGlyph\n*GlyphInspector.evaluateGlyphs assigns a shape when possible\n===\n++++!![LEAVES_COMPOUNDS]>\n*See ~SYMBOLS_COMPOUNDS with a different doubt threshold\n===\n++++!![CLEANUP]>\n*GlyphInspector.verifySystemStems\n##GlyphsBuilder.removeSystemInactives (removed from system, sections are not cut)\n##For system ''active glyphs'' for which __shape == COMBINING_STEM__ and which have no adjacent ''section'' compliant with reliable StemSymbols (shape contained in StemSymbols : BEAM, BEAM_HOOK, NoteHeads, Flags, HeadAndFlags, though BEAM_HOOK is not sufficient)\n##These suspectedStems glyphs are removed and their sections cut\n##Then GlyphsBuilder.extractNewSystemGlyphs (removeSystemInactives, retrieveSystemGlyphs)\n##Evaluation with specific doubt threshold (could be GlyphInspector.evaluateGlyphs at system level !!!)\n##Member sections of former suspectedStems are checked. If none assigned to a glyph which isWellKnown, then the glyph is removed and the former stem is re-inserted by GlyphsBuilder.insertGlyph\n##Finally GlyphsBuilder.extractNewSystemGlyphs (removeSystemInactives, retrieveSystemGlyphs)\n*GlyphInspector.verifySystemSlurs\n**GlyphsBuilder.removeSystemInactives (removed from system, sections are not cut)\n**For system ''active glyphs'' for which __shape == SLUR__\n**If distance to approximating circle is computed\n**Small slurs: \n###try to aggregate with suitable glyphs __(!isKnown || (SLUR && !circle.isValid) || (!isManualShape && (CLUTTER || doubt >= minDoubt))__.\n###Accepted compound slurs as inserted by GlyphsBuilder.insertCompound()\n**Large slurs:\n###Search through the slur member sections the best seed (section with significant size and best circle distance).\n###Then add incrementally by decreasing weight the other sections with correct circle distance.\n###Final slur glyph is inserted by GlyphsBuilder.insertGlyph.\n###Former slur glyph is removed (sections not cut).\n###Sections left over are assigned a null glyph.\n**Finally GlyphsBuilder.extractNewSystemGlyphs (removeSystemInactives, retrieveSystemGlyphs)\n*GlyphInspector.evaluateGlyphs assigns a shape when possible\n===\n++++!![SCORE]\n===\n++++!![Interactive Actions]>\n*StemSegment\n##Deassign the selected active glyph(s)\n##Collect ''sections'' from members of these glyph(s)\n##Use a VerticalArea which filters these sections through (__glyph==null || !glyph.isWellKnown__)\n##VerticalsBuilder.retrieveVerticals on the area sticks\n===\n===\n
! Ideas related to glyph processing\n
The idea is to make sure we reuse the same (remanent) Glyph entity when, by whatever construction, we come up with a glyph which is identical to an existing one.\nDoing so, the glyph ID would really be meaningful.\nThis verification could take place when a glyph is really "//inserted//" in the ~GlyphLag.\n\nDone. When a glyph is inserted into the ~GlyphLag, its signature is checked against existing ones. If a match is found, the reference of the existing one is returned, otherwise a brand new one is created and its reference returned.
Use HeadAndFlag symbols all the way to score building.\nActually such a construction is a symbol with stable shape, so proper information regarding note head and number of flags can be easily derived from the recognized symbol.\nHere is an example of two such symbols, which are now properly recognized :\n*On the left, a ~HEAD_AND_FLAG_1_UP\n*On the right a ~HEAD_AND_FLAG_2_UP\n[img[Two examples of head + flag|images/head-and-flag.jpg]]
Use bestNote pitch position for better precision of chord headLocation.y
[[TiddlyWiki for the rest of us|http://www.giffmex.org/twfortherestofus.html]]
Full name : Hervé Bitteur\nContact: [[Email|mailto://herve.bitteur@laposte.net]]\nOwner of projects :\n*[[Audiveris|https://audiveris.dev.java.net]]\n*[[ProxyMusic|https://proxymusic.dev.java.net]]
Part of Brenton patches, to gracefully handle the case where icons are not available:\n*Look into the /icons folder, when an icon is not found in the resources bundle as it should be\n*Avoid throwing exceptions in ScorePainter
This is the ability to detect a very first measure (number="0", implicit="yes") whose duration is much shorter than the other measures.\nConditions could be :\n*Very first measure of the very first system (of the very first page) of the score\n*Same computed duration for all parts (as usual a ''whole'' rest gives no specific duration)
This feature is dependent upon the more general question of OpticalCharacterRecognition\nDone in V3.2, thanks to the integration of Tesseract
Main Content\n\nAllOpenItems\nAllClosedItems\nAllInfoItems\nRecordareExamples
The layout of the main window should be improved.\nHere is the current version :\n[img[Current main window layout|images/main-window.png notFound]]\nWe should get rid of the global action buttons\nDone, no more global action buttons
There is a memory leak, since the memory remains high after closing both the Sheet and the Score entities.\nTo be investigated with proper tools (''jmap'' and ''jhat'' in Java 6).\n\nLeak has been fixed (it was due to ~SheetManager selection still pointing to the defunct Sheet instance).
We should start thinking about a more ''modular'' way of invoking the various processing actions.\nRather than the very sequential steps, the interactive user will need the ability to make a correction on what he can see (which means mainly from the ''Glyphs'' view), regardless of where and in which step the exact processing is located. Examples :\n*Discovering that a stem has not been isolated, because the symbol had been initially mistaken for some well known shape, preventing the stem segmenting. It's currently no use to deassign the glyph, this will not trigger the "stem-segmentation" of the glyph.\n*Corrections concerning Slurs should be doable from the ''Glyphs'' view, and not only run automatically in the Cleanup step.\nIn terms of modularity, we should investigate to @@work at the System level@@ :\n*Once the systems have been identified (and perhaps checked by the user), isolation should be doable most of the time.\n*Thus a modification could trigger the rebuilding of many steps ''within'' this system only\nIn terms of buffering, when several user actions are done in one shot, such as assigning the CLUTTER shape to a bunch of glyphs, we should carry out all the assignments, and only at the end call the needed rebuild.\n\nIdeas to be investigated :\n*Use of SectionGlyphRelation\n*Basic user actions\n**Stem-segment this selected glyph\n**Merge these selected glyphs\n*Define user transactions as such\n**Which should be handled as a whole. For example, all individual modifications should be performed, before further interpretation or system update is triggered.\n\nNow, most of the processing is performed System per System (even in parallel, see [[Parallelism]]).
We have to implement the notion of page, one page for one sheet, several pages making a score.\nOr are we sure we can simply play with mosaic of several images into one single sheet?
[[MusicXML definition on Recordare site|www.recordare.com/xml.html]]
/***\n|Name|NestedSlidersPlugin|\n|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|\n|Version|2.0.0|\n|Author|Eric Shulman - ELS Design Studios|\n|License|http://www.TiddlyTools.com/#LegalStatements <<br>>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|\n|~CoreVersion|2.1|\n|Type|plugin|\n|Requires||\n|Overrides||\n|Description||\n\nQuickly make any tiddler content into an expandable 'slider' panel, without needing to create a separate tiddler to contain the slider content. Optional syntax allows ''default to open'', ''custom button label/tooltip'' and ''automatic blockquote formatting.''\n\nYou can also 'nest' these sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created. This is most useful when converting existing in-line text content to create in-line annotations, footnotes, context-sensitive help, or other subordinate information displays.\n\nFor more details, please click on a section headline below:\n++++!!!!![Configuration]>\nDebugging messages for 'lazy sliders' deferred rendering:\n<<option chkDebugLazySliderDefer>> show debugging alert when deferring slider rendering\n<<option chkDebugLazySliderRender>> show debugging alert when deferred slider is actually rendered\n===\n++++!!!!![Usage]>\nWhen installed, this plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content. Use {{{+++}}} and {{{===}}} to delimit the slider content. Additional optional syntax elements let you specify\n*default to open\n*cookiename\n*heading level\n*floater (with optional CSS width value)\n*mouse auto rollover\n*custom class/label/tooltip/accesskey\n*automatic blockquote\n*deferred rendering\nThe complete syntax, using all options, is:\n//{{{\n++++(cookiename)!!!!!^width^*{{class{[label=key|tooltip]}}}>...\ncontent goes here\n===\n//}}}\nwhere:\n* {{{+++}}} (or {{{++++}}}) and {{{===}}}^^\nmarks the start and end of the slider definition, respectively. When the extra {{{+}}} is used, the slider will be open when initially displayed.^^\n* {{{(cookiename)}}}^^\nsaves the slider opened/closed state, and restores this state whenever the slider is re-rendered.^^\n* {{{!}}} through {{{!!!!!}}}^^\ndisplays the slider label using a formatted headline (Hn) style instead of a button/link style^^\n* {{{^width^}}} (or just {{{^}}})^^\nmakes the slider 'float' on top of other content rather than shifting that content downward. 'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.). If omitted, the default width is "auto" (i.e., fit to content)^^\n* {{{*}}}^^\nautomatically opens/closes slider on "rollover" as well as when clicked^^\n* {{{{{class{[label=key|tooltip]}}}}}}^^\nuses custom label/tooltip/accesskey. {{{{{class{...}}}}}}, {{{=key}}} and {{{|tooltip}}} are optional. 'class' is any valid CSS class name, used to style the slider label text. 'key' must be a ''single letter only''. Default labels/tootips are: ">" (more) and "<" (less), with no default access key assignment.^^\n* {{{">"}}} //(without the quotes)//^^\nautomatically adds blockquote formatting to slider content^^\n* {{{"..."}}} //(without the quotes)//^^\ndefers rendering of closed sliders until the first time they are opened. //Note: deferred rendering may produce unexpected results in some cases. Use with care.//^^\n\n//Note: to make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the {{{+++}}} 'start slider' or preceding the {{{===}}} 'end slider' sequence are automatically supressed so that excess whitespace is eliminated from the output.//\n===\n++++!!!!![Examples]>\nsimple in-line slider: \n{{{\n+++\n content\n===\n}}}\n+++\n content\n===\n----\nuse a custom label and tooltip: \n{{{\n+++[label|tooltip]\n content\n===\n}}}\n+++[label|tooltip]\n content\n===\n----\ncontent automatically blockquoted: \n{{{\n+++>\n content\n===\n}}}\n+++>\n content\n===\n----\nall options combined //(default open, cookie, heading, sized floater, rollover, class, label/tooltip/key, blockquoted, deferred)//\n{{{\n++++(testcookie)!!!^30em^*{{big{[label=Z|click or press Alt-Z to open]}}}>...\n content\n===\n}}}\n++++(testcookie)!!!^30em^*{{big{[label=Z|click or press Alt-Z to open]}}}>...\n content\n===\n----\ncomplex nesting example:\n{{{\n+++^[get info...=I|click for information or press Alt-I]\n put some general information here, plus a floating slider with more specific info:\n +++^10em^[view details...|click for details]\n put some detail here, which could include a rollover with a +++^25em^*[glossary definition]explaining technical terms===\n ===\n===\n}}}\n+++^[get info...=I|click for information or press Alt-I]\n put some general information here, plus a floating slider with more specific info:\n +++^10em^[view details...|click for details]\n put some detail here, which could include a rollover with a +++^25em^*[glossary definition]explaining technical terms===\n ===\n===\n===\n!!!!!Installation\n<<<\nimport (or copy/paste) the following tiddlers into your document:\n''NestedSlidersPlugin'' (tagged with <<tag systemConfig>>)\n<<<\n!!!!!Revision History\n<<<\n''2006.07.28 - 2.0.0'' added custom class syntax around label/tip/key syntax: {{{{{classname{[label=key|tip]}}}}}}\n''2006.07.25 - 1.9.3'' when parsing slider, save default open/closed state in button element, then in onClickNestedSlider(), if slider state matches saved default, instead of saving cookie, delete it. Significantly reduces the 'cookie overhead' when default slider states are used.\n''2006.06.29 - 1.9.2'' in onClickNestedSlider(), when setting focus to first control, skip over type="hidden"\n''2006.06.22 - 1.9.1'' added panel.defaultPanelWidth to save requested panel width, even after resizing has changed the style value\n''2006.05.11 - 1.9.0'' added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label\n''2006.05.09 - 1.8.0'' in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element\n''2006.04.24 - 1.7.8'' in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position\n''2006.02.16 - 1.7.7'' corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie\n''2006.02.15 - 1.7.6'' in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)\n''2006.02.04 - 1.7.5'' add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals\n''2006.01.18 - 1.7.4'' only define adjustSliderPos() function if it has not already been provided by another plugin. This lets other plugins 'hijack' the function even when they are loaded first.\n''2006.01.16 - 1.7.3'' added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels. While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels. Short-term workaround is to only adjust the position for 'top-level' floaters.\n''2006.01.16 - 1.7.2'' added button property to slider panel elements so that slider panel can tell which button it belongs to. Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends\n''2006.01.14 - 1.7.1'' added optional "^" syntax for floating panels. Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.\n''2006.01.14 - 1.7.0'' added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)\n''2006.01.03 - 1.6.2'' When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element. (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)\n''2005.12.15 - 1.6.1'' added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders\nremoved checkbox option for 'global' application of lazy sliders\n''2005.11.25 - 1.6.0'' added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)\n''2005.11.21 - 1.5.1'' revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability. Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.\n''2005.11.20 - 1.5.0'' added (cookiename) syntax for optional tracking and restoring of slider open/close state\n''2005.11.11 - 1.4.0'' added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style\n''2005.11.07 - 1.3.0'' removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other\nformatting extensions) and simplified/improved regular expressions to trim multiple excess newlines\n''2005.11.05 - 1.2.1'' changed name to NestedSlidersPlugin\nmore documentation\n''2005.11.04 - 1.2.0'' added alternative character-mode syntax {{{(((}}} and {{{)))}}}\ntweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax\n''2005.11.03 - 1.1.1'' fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used\ncode cleanup, added documentation\n''2005.11.03 - 1.1.0'' changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}\nchanged name to EasySlidersPlugin\n''2005.11.03 - 1.0.0'' initial public release\n<<<\n!!!!!Credits\n<<<\nThis feature was implemented by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]] with initial research and suggestions from RodneyGomes, GeoffSlocock, and PaulPetterson.\n<<<\n!!!!!Code\n***/\n//{{{\nversion.extensions.nestedSliders = {major: 2, minor: 0, revision: 0, date: new Date(2006,7,28)};\n//}}}\n\n//{{{\n// options for deferred rendering of sliders that are not initially displayed\nif (config.options.chkDebugLazySliderDefer==undefined) config.options.chkDebugLazySliderDefer=false;\nif (config.options.chkDebugLazySliderRender==undefined) config.options.chkDebugLazySliderRender=false;\n\n// default styles for 'floating' class\nsetStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \s\n background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");\n//}}}\n\n//{{{\nconfig.formatters.push( {\n name: "nestedSliders",\n match: "\s\sn?\s\s+{3}",\n terminator: "\s\ss*\s\s={3}\s\sn?",\n lookahead: "\s\sn?\s\s+{3}(\s\s+)?(\s\s([^\s\s)]*\s\s))?(\s\s!*)?(\s\s^(?:[^\s\s^\s\s*\s\s[\s\s>]*\s\s^)?)?(\s\s*)?(?:\s\s{\s\s{([\s\sw]+[\s\ss\s\sw]*)\s\s{)?(\s\s[[^\s\s]]*\s\s])?(?:\s\s}{3})?(\s\s>)?(\s\s.\s\s.\s\s.)?\s\ss*",\n handler: function(w)\n {\n // defopen=lookaheadMatch[1]\n // cookiename=lookaheadMatch[2]\n // header=lookaheadMatch[3]\n // panelwidth=lookaheadMatch[4]\n // rollover=lookaheadMatch[5]\n // class=lookaheadMatch[6]\n // label=lookaheadMatch[7]\n // blockquote=lookaheadMatch[8]\n // deferred=lookaheadMatch[9]\n\n lookaheadRegExp = new RegExp(this.lookahead,"mg");\n lookaheadRegExp.lastIndex = w.matchStart;\n var lookaheadMatch = lookaheadRegExp.exec(w.source)\n if(lookaheadMatch && lookaheadMatch.index == w.matchStart)\n {\n // location for rendering button and panel\n var place=w.output;\n\n // default to closed, no cookie, no accesskey\n var show="none"; var title=">"; var tooltip="show"; var cookie=""; var key="";\n\n // extra "+", default to open\n if (lookaheadMatch[1])\n { show="block"; title="<"; tooltip="hide"; }\n\n // cookie, use saved open/closed state\n if (lookaheadMatch[2]) {\n cookie=lookaheadMatch[2].trim().slice(1,-1);\n cookie="chkSlider"+cookie;\n if (config.options[cookie]==undefined)\n { config.options[cookie] = (show=="block") }\n if (config.options[cookie])\n { show="block"; title="<"; tooltip="hide"; }\n else\n { show="none"; title=">"; tooltip="show"; }\n }\n\n // parse custom label/tooltip/accesskey: [label=X|tooltip]\n if (lookaheadMatch[7]) {\n title = lookaheadMatch[7].trim().slice(1,-1);\n var pos=title.indexOf("|");\n if (pos!=-1) { tooltip = title.substr(pos+1,title.length); title=title.substr(0,pos); }\n if (title.substr(title.length-2,1)=="=") { key=title.substr(title.length-1,1); title=title.slice(0,-2); }\n if (pos==-1) tooltip += " "+title; // default tooltip: "show/hide <title>"\n }\n\n // create the button\n if (lookaheadMatch[3]) { // use "Hn" header format instead of button/link\n var lvl=(lookaheadMatch[3].length>6)?6:lookaheadMatch[3].length;\n var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,lookaheadMatch[6],title);\n btn.onclick=onClickNestedSlider;\n btn.setAttribute("href","javascript:;");\n btn.setAttribute("title",tooltip);\n }\n else\n var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,lookaheadMatch[6]);\n\n // set extra button attributes\n btn.sliderCookie = cookie; // save the cookiename (if any) in the button object\n btn.defOpen=lookaheadMatch[1]!=null; // save default open/closed state (boolean)\n btn.keyparam=key; // save the access key letter ("" if none)\n if (key.length) {\n btn.setAttribute("accessKey",key); // init access key\n btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus\n }\n\n // "non-click" MouseOver open/close slider\n if (lookaheadMatch[5]) btn.onmouseover=onClickNestedSlider;\n\n // create slider panel\n var panelClass=lookaheadMatch[4]?"floatingPanel":"sliderPanel";\n var panel=createTiddlyElement(place,"div",null,panelClass,null);\n panel.button = btn; // so the slider panel know which button it belongs to\n panel.defaultPanelWidth=(lookaheadMatch[4] && lookaheadMatch[4].length>2)?lookaheadMatch[4].slice(1,-1):""; // save requested panel size\n btn.sliderPanel=panel;\n panel.style.display = show;\n panel.style.width=panel.defaultPanelWidth;\n\n // render slider (or defer until shown) \n w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;\n if ((show=="block")||!lookaheadMatch[9]) {\n // render now if panel is supposed to be shown or NOT deferred rendering\n w.subWikify(lookaheadMatch[8]?createTiddlyElement(panel,"blockquote"):panel,this.terminator);\n // align slider/floater position with button\n adjustSliderPos(place,btn,panel,panelClass);\n }\n else {\n var src = w.source.substr(w.nextMatch);\n var endpos=findMatchingDelimiter(src,"+++","===");\n panel.setAttribute("raw",src.substr(0,endpos));\n panel.setAttribute("blockquote",lookaheadMatch[8]?"true":"false");\n panel.setAttribute("rendered","false");\n w.nextMatch += endpos+3;\n if (w.source.substr(w.nextMatch,1)=="\sn") w.nextMatch++;\n if (config.options.chkDebugLazySliderDefer) alert("deferred '"+title+"':\sn\sn"+panel.getAttribute("raw"));\n }\n }\n }\n }\n)\n\n// TBD: ignore 'quoted' delimiters (e.g., "{{{+++foo===}}}" isn't really a slider)\nfunction findMatchingDelimiter(src,starttext,endtext) {\n var startpos = 0;\n var endpos = src.indexOf(endtext);\n // check for nested delimiters\n while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {\n // count number of nested 'starts'\n var startcount=0;\n var temp = src.substring(startpos,endpos-1);\n var pos=temp.indexOf(starttext);\n while (pos!=-1) { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }\n // set up to check for additional 'starts' after adjusting endpos\n startpos=endpos+endtext.length;\n // find endpos for corresponding number of matching 'ends'\n while (startcount && endpos!=-1) {\n endpos = src.indexOf(endtext,endpos+endtext.length);\n startcount--;\n }\n }\n return (endpos==-1)?src.length:endpos;\n}\n//}}}\n\n//{{{\nwindow.onClickNestedSlider=function(e)\n{\n if (!e) var e = window.event;\n var theTarget = resolveTarget(e);\n var theLabel = theTarget.firstChild.data;\n var theSlider = theTarget.sliderPanel\n var isOpen = theSlider.style.display!="none";\n // if using default button labels, toggle labels\n if (theLabel==">") theTarget.firstChild.data = "<";\n else if (theLabel=="<") theTarget.firstChild.data = ">";\n // if using default tooltips, toggle tooltips\n if (theTarget.getAttribute("title")=="show")\n theTarget.setAttribute("title","hide");\n else if (theTarget.getAttribute("title")=="hide")\n theTarget.setAttribute("title","show");\n if (theTarget.getAttribute("title")=="show "+theLabel)\n theTarget.setAttribute("title","hide "+theLabel);\n else if (theTarget.getAttribute("title")=="hide "+theLabel)\n theTarget.setAttribute("title","show "+theLabel);\n // deferred rendering (if needed)\n if (theSlider.getAttribute("rendered")=="false") {\n if (config.options.chkDebugLazySliderRender)\n alert("rendering '"+theLabel+"':\sn\sn"+theSlider.getAttribute("raw"));\n var place=theSlider;\n if (theSlider.getAttribute("blockquote")=="true")\n place=createTiddlyElement(place,"blockquote");\n wikify(theSlider.getAttribute("raw"),place);\n theSlider.setAttribute("rendered","true");\n }\n // show/hide the slider\n if(config.options.chkAnimate)\n anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));\n else\n theSlider.style.display = isOpen ? "none" : "block";\n // reset to default width (might have been changed via plugin code)\n theSlider.style.width=theSlider.defaultPanelWidth;\n // align slider/floater position with target button\n if (!isOpen) adjustSliderPos(theSlider.parentNode,theTarget,theSlider,theSlider.className);\n // if showing panel, set focus to first 'focus-able' element in panel\n if (theSlider.style.display!="none") {\n var ctrls=theSlider.getElementsByTagName("*");\n for (var c=0; c<ctrls.length; c++) {\n var t=ctrls[c].tagName.toLowerCase();\n if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")\n { ctrls[c].focus(); break; }\n }\n }\n if (this.sliderCookie && this.sliderCookie.length) {\n config.options[this.sliderCookie]=!isOpen;\n if (config.options[this.sliderCookie]!=this.defOpen)\n saveOptionCookie(this.sliderCookie);\n else { // remove cookie if slider is in default display state\n var ex=new Date(); ex.setTime(ex.getTime()-1000);\n document.cookie = this.sliderCookie+"=novalue; path=/; expires="+ex.toGMTString();\n }\n }\n return false;\n}\n\n// hijack animation handler 'stop' handler so overflow is visible after animation has completed\nSlider.prototype.coreStop = Slider.prototype.stop;\nSlider.prototype.stop = function() { this.coreStop(); this.element.style.overflow = "visible"; }\n\n// adjust panel position based on button position\nif (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel,panelClass) {\n if (panelClass=="floatingPanel") {\n var left=0;\n var top=btn.offsetHeight; \n if (place.style.position!="relative") {\n var left=findPosX(btn);\n var top=findPosY(btn)+btn.offsetHeight;\n var p=place; while (p && p.className!='floatingPanel') p=p.parentNode;\n if (p) { left-=findPosX(p); top-=findPosY(p); }\n }\n if (left+panel.offsetWidth > getWindowWidth()) left=getWindowWidth()-panel.offsetWidth-10;\n panel.style.left=left+"px"; panel.style.top=top+"px";\n }\n}\n\nfunction getWindowWidth() {\n if(document.width!=undefined)\n return document.width; // moz (FF)\n if(document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )\n return document.documentElement.clientWidth; // IE6\n if(document.body && ( document.body.clientWidth || document.body.clientHeight ) )\n return document.body.clientWidth; // IE4\n if(window.innerWidth!=undefined)\n return window.innerWidth; // IE - general\n return 0; // unknown\n}\n//}}}
This is really an impressive (yet rather small) piece of software.\nAudiveris uses a standard configuration of just one hidden layer. As of this writing, the figures are :\n*12 cells in the input layer (10 moments, plus 2 characteristics : presence of ledger, number of stems)\n*113 cells in the hidden layer\n*113 cells in the output layer (the number of symbol shapes to directly recognize)\n\nReally amazing ...
Make sure a voice cannot contain several chords of the same slot, they appear as vertical voice segments.\nThis was a bug in Slot.buildVoices(), now fixed.
Whole rest appear as not having a related voice. This is not correct.\nBug was due to the fact that voices were set only through slot browsing, and whole rests belong to no slot.\nFixed.
Force the ordinates of note heads for cases where a flag or some other stuff is stuck to the head(s) glyph.\nUse the difference between centroid and area center ordinates to detect the case
The idea is to be able to directly use the current (official) mapping for any section. Typically the toString() method for section would use this default mapping, and the GlyphLag as well.\n*Since this binding is the default, the question is now to record the previous binding if any. Typically this should take place in the section.setGlyph method, with a GlyphMap parameter where the ''previous'' binding, if any, will be recorded.\n*Some analysis is needed to determine the proper (set of) glyph maps.\n*This opens the way to rather easy way to implement UnDo and ReDo actions.\n*By default, the program will go as far as it sees fit, and then let the user play interactively with the result to make manual modifications (with ability to try and check).
This is an important topic, for which we have to find a separate Java implementation (compatible with the Open Source license of Audiveris)\nOCR features would allow [[Lyrics]], recognition of notations words, of title, composer, etc... \n\nDone in V3.2, via Tesseract.\nThis is limited to Windows for the time being however.
We should investigate proper usage of parallel machines (such as Intel Core 2 Duo PCs), and specifically which areas could benefit from parallelism defined at algorithmic level.\n*We could use one thread per System instance in the score.\n*Some benchmark analysis should be done beforehand, to work on areas with highest possible gains.\n\nProfiler indicate that RunsBulder.createRuns eats a lot of CPU. It could be parallelized, one thread per column.\n\nDone and checked with a Core 2 Duo, a true multi-processor machine which revealed some bugs unseen so far (most have been fixed)\nRunsBuilder uses one task per column.\nScoreBuilder uses one task per System.\nTwo executors have been made available, one for high priority and one for low priority.\n\nAlso the step handling has been revamped and now uses a dedicated omr.step package.\nHowever the SCORE step cannot have its systems processed in parallel, while the previous ones (from SYMBOLS up to CLEANUP) can be processed that way. For the time being, this system parallelism has been disabled as a whole. Future work should address this topic with a separation between the system steps (in parallel) and the final SCORE step serialized.
Remove ~PitchPosition as a parameter for Neural Network as this implies a too strong dependency on pitch position (or would require a lot more training samples).\nInstead, implement post-recognition additional checks.\nThis is now done, but GlyphAdditionalChecks would deserve a more systematic approach than provided by the current implementation
Use icon refPoint (rather than glyph center) to more precisely position flats (accidentals and signatures) with the proper pitch position
This section describes how each of the 12 PDF examples of the Recordare web site can be processed with Audiveris:\n#[[ActorPreludeSample.pdf]]\n#[[BeetAnGeSample.pdf]]\n#[[BrahWiMeSample.pdf]]\n#[[BrookeWestSample.pdf]]\n#[[DebuMandSample.pdf]]\n#[[Dichterliebe01.pdf]]\n#[[FaurReveSample.pdf]]\n#[[HandJuMa36Excerpt.pdf]]\n#[[MahlFaGe4Sample.pdf]]\n#[[MozaChloSample.pdf]]\n#[[MozaVeilSample.pdf]]\n#[[SchbAvMaSample.pdf]]\n
||carmen-1|M19|Beam & BeamHook not attached to stem|\n||carmen-1|M20|Should set this measure as implicit, or ignore it?|\n||allegretto|M5|Beams not correctly handled|\n||allegretto|M6|Cannot force a glyph to a stem|\n||allegretto|M12|Several glyphs to be split|\n||batuque|M5|measure w/ just clef, should be ignored?|\n||country|M4|Tuplet w/o beams|\n||DebuMandSample-250|M11|A flat (B) is translated as a key signature|\n|fixed|estudio|M2|short stem not detected|\n||hove||Error with shape multi_rest|\n||MahlFaGe4Sample-250|M11|5/4 as time signature|\n|dialog|MozaChloSample-250||Systems w/ different nb of staves|\n|dialog|chbAvMaSample-250||Systems w/ different nb of staves|\n||Straight_Page_1|M23|Cannot merge slur chunks 869 & 872|\n||Straight_Page_1|M21|Cannot connect slur chunks 855|\n|dialog|tzigane2||IndexOutOfBoundsException in BarsBuilder|\n|dialog|ucb12_111_125-2||Picture resolution is too low. Stop!!!|\n|fixed|zizi|M5|Strange measure too long|\n|fixed|blonde|M12|Stem mistaken for a barline, cannot correct|\n||canon|M15|barline not recognized, can be assigned, w/o result|\n|fixed|carmen-2||IndexOutOfBoundsException in colorize for HorizontalsBuider|\n||contredanse|M3|Sharp sign linked to just one note head although the note is duplicated|\n||contredanse|M5|A pack of note heads: 1 void & 2 blacks|\n
Make the toString() method more robust againt non-initialized members (Brenton patch)\nThese methods were called during construction of instance of subclassed of ScoreNode. During the addChild() method, the instance was tried to be printed out, though not yet fully initialized.
For the time being, score entities are "translated" from glyph shapes.\nWe first need to make sure that any shape can thus be assigned (and deassigned) to a target glyph, so as to be translated to the proper score entity.\n\nBut what if we don't have a defined glyph to be assigned the desired shape?\n*Perhaps we should be able to split glyphs into smaller glyphs (but thia may not be sufficient in all cases)\n*And/or we should investigate the possibility to directly inject some score entity, regardless of any underlying glyph. We would get closer to a score editor than a glyph translator, so how far are we ready to go this way?
++++![Shape]>\nShapes are unmutable definitions\n*isWellKnown() : (this != ~NO_LEGAL_SHAPE) && (this != NOISE) && (this != STRUCTURE) \n===\n++++![Glyph]>\nA Glyph is a rather volatile combination of member sections. Different glyphs can have sections in common, via their collection Glyph -> member Sections, but the truth is in the link Section -> Glyph\n*isActive() : all its member sections point to this containing glyph\n*isKnown() : (shape != null) && (shape != Shape.NOISE)\n*isSuccessful() : result instanceof SuccessResult\n*isWellKnown() : (shape != null) && shape.isWellKnown())\n===\n++++![GlyphSection]>\nThe truth is in the sections. While glyphs may come and go, sections are never modified regarding their composition of runs of pixels\n*isKnown() : (glyph != null) && (glyph.isSuccessful() || glyph.isWellKnown())\n===
''~StickRelation''\n*This refers initially to the data which should actually be carried by the relation between a Section and a Stick : ''role'', ''layer'', ''direction'', line?\n**Actually the '''line''' information is intrinsically part of the section since it carries all the data points and are simply used when checking compatible slopes in skew detection, or when building the section (line) data points.\n**So let's separate line (into the ~StickSection class) and the ~StickRelation as a class by itself.\n*It is today written directly into the ~StickSection, while this information is needed only //''during''// the stick building. The solution will consist in a Map<Section,~StickRelation> which would keep this information separate from the actual Section.\n\nDone, in the sense that the ~StickRelation is a separate structure which encapsulates the data for this relationship. However, a pointer to a potential ~StickRelation is kept in the Glyph, there is no map as initially suggested.
The disruptive idea is to ''separate'' and handle the mapping data from the sections themselves. The same idea could lead to :\n*A Map<Section,Glyph> and a Map<Section,Stick> or a Map<Section,Stem>.\n*In fact the "stick sections" could be defined once and for all within each connected glyph, and either used or not. They could be used to actually separate stems and leaves, when the stick is checked as a stem, or simply to help the recognition of such symbols as Sharps, Naturals, etc... When retrieving Leaves rather than Glyphs, it suffices to take into account the Map<Section,Stem> to detect which sections should be used to build up the leaves and which should be left over as being assigned to a stem.\n*Keeping this information in separate maps, rather than written directly within the section, should lead to a cleaner situation. The Section does not have to be aware of the potential usages of all maps around. It's easier to erase, easier to keep several maps around, according to the purpose at hand. We also have the ability to copy part or whole of a map into a larger map.\n*Such "parallel" maps could be handled on a per system basis, to improve performance.\n*Perhaps this could help reduce the number of ~LagViews the user has to play with. To be investigated.\n\nHow to handle the evolution ? (Limit big bang as much as possible)\n#(done) Begin with the ~StickRelation in the current architecture\n#(partly) Then implement the Section -> Glyph relationship via a map\n#(done) Make a ~GlyphLag host a default map\n#Consider several maps per System\n#Implement the glyph uniqueness (no aliases for the same physical glyph)\n#Finally, move to a more tiny use of these mappings\n\nFor tomorrow :\n*General use of SectionPredicate\n*Use of SticksBuilder (VerticalArea, etc) to be cleaned up\n*Clean use of glyphMap and relationMap\n\nEvolution : Foster a single view, with the ability for the user to play with the glyph at hand.\n*Today, we have a sequence of steps that are applied to all glyphs (almost one view par step). It's diffcult to go back (example of a non-detected stem)\n*Tomorrow, we should be able to work in the context of one glyph (the one which is selected by the user for example) and make a whole sequence of micro-steps on this glyph and its constituents. Perhaps, using some "what if" display, and ask the user to validate the result ?\n\nMaps : Besides the relationMaps which are relevant only during the building of sticks, we could take advantage from the availability of several maps :\n*symbolMap : section -> symbol glyph\n*stemMap : section -> stem stick\n*leafMap : section -> leaf glyph\n*compoundMap : section -> compound glyph\nQuestion : where should we find all the maps ?\n*perhaps a global glyphMap (to record the official current assignments)\n*perhaps a glyph could point to its (sub) maps ?\n\nFinally we keep the link from Section to Glyph, rather than a separate Map
Where are the glyphs really handled? We have two levels:\n*The global Sheet level, represented by the //__vLag__// GlyphLag instance of the Sheet instance\n*The local System level, represented by the //__glyphs__// instance of each System instance in the Sheet\nThey are kept in sync, whenever we add or discard a glyph:\n*The GlyphLag has one method addGlyph() which adds a glyph to the global collection of glyphs (it actually returns the true glyph, either this brand new one, or an already existing one)\n*addGlyph is called by :\n**SkewBuilder (within sLag, no notion of system)\n**SticksBuilder.createSticks\n***Handles a collection of sticks\n***hLag : for LineBuilder (line & hole) & HorizontalsBuilder\n***vLag : \n****by BarsBuilder. True bar sticks are then split between systems glyphs.\n****by VerticalsBuilder. Sticks are split between systems vSticks, and true stems are inserted in system glyphs.\n**GlyphsBuilder.insertGlyph (within vLag)\n***After inserting in GlyphLag, this method also inserts in relevant SystemInfo\n
A notebook about Audiveris work in progress
Audiveris Notebook
Slurs have specific questions still to be solved :\nCirclesVsEllipses\nAssigningSlursToParts\nSpuriousSlurs\nExportingSlurs\nSlursAndVoices
Use Slurs (actually ties) to detect lengthened notes, and implement their impact to Voice algorithm.\nDone
Develop a ''split'' operation for user interaction (a kind of reverse of the Compound building), in order to segment connected glyphs and rebuild the proper items.\nWhich heuristics should be used? A good one works specifically for large Slurs (see SpuriousSlurs). What can we think of for the other ones ?\nActually, a simple "deassign" on the compound glyph does the split.\nThe only problem left is that the "deassign" action is disabled if the compound has no assigned shape. To be investigated.\n\nIn V3.2, the user can work at section level (in addition to the standard glyph level). This provides many possibilities for splitting glyphs.
Glyphs are often assigned a Beam shape, simply because of their connection to one or two stems.\n* Here, we have a Slur which crosses a stem :\n[img[Wrong shape assigned|images/beam-spurious.jpg]] It is assigned the BEAM shape, with a doubt value of 1.008\nSimply de-assigning the glyph, will make it build a compound with its neighbors, and be recognized as a Slur :\n[img[Right slur shape recognized|images/beam-deassigned.jpg]] It is assigned the SLUR shape, with a doubt value of 1.000, much better than the initial value.\n\nThis gives me the idea of relaxing the compound attempts : even the well assigned shapes should be called into question and changed for a better compound shape if any.\n\n* Another example, where a Slur is stuck with a Flag, resulting in a spurious Beam :\n[img[Wrong Beam assignment|images/beam-stuck.jpg]]\nand after deassign of the two spurious Beams, the result is a (wrong) Slur compound :\n[img[Wrong Slur compound|images/beam-stuck-deassigned.jpg]]\nIn this case, the (wrong) Slur should be segmented, looking for true circle portions and discarding the rest.
! Glyph Shape\n* Some glyphs are assigned a shape during preliminary stages using procedural logic based on structure data. This strategy applies for :\n** Ledgers (via horizontal sticks)\n** Barlines (via vertical sticks)\n* The wide majority of glyphs are recognized thanks to the Neural Network module. This accounts for all glyphs with specific shape. In fact, the output of Neural Network is not immediately made public, it has to go through a small stage that perform additional checks depending on the detected shape.\n** This is the case for Time signature, for which the pitch position is checked to lie precisely between the score lines.\n* Even later, additional checks may be performed, using generally more contextual information\n** SpuriousSlurs are a good example of additional checks, with related additional segmentation/aggregation possibilities\n** SpuriousBeams can also be detected.\n* Finally, all remaining spurious glyphs should be collected and presented as a kind of BrowsableSpuriousCollection to the user, who would have thus the ability to take proper actions.
For Slurs with poor distance, two actions can be thought of (to be validated via the computed curve distance) :\n* ''Small slurs'' may be //combined// with nearby glyphs, typically other Slur, or Clutter. Today a tentative compound is valid if and only if the resulting compound doubt value is smaller than the doubt on the initial glyph. We could go beyond this, and (for Slurs only of course) use the curve distance as the proper validation check. Here are two similar examples :\n**Before merging: [img[Two slur portions|images/slur-short.jpg]] and after merging the 2 glyphs : [img[Slur compound once recognized|images/slur-short-compound.jpg]]\n**Before merging: [img[Before merging|images/slur-short-2.jpg]] and after merging the 2 glyphs : [img[After merging|images/slur-short-compound-2.jpg]]\n\n* ''Large slurs'' may be //segmented// and rebuilt incrementally section after section, while checking the curve distance. The sections left over could then be recombined (using usual connectivity) to form separate glyphs, to be later recognized.\n**Here is on the first picture an example of a long slur with a stuck object (a natural sign). Notice the circle which does not really fit the slur. \n**And the corresponding Section details on the second picture. Obviously, combining the right sections for the slur should be rather easy :\nGlyphs : [img[Glyph view of a long slur|images/slur-long.jpg]] Sections : [img[Section view of the same long slur|images/slur-long-sections.jpg]]\n\nHere is how this example of large slur is now fixed (notice that besides the correct Slur, the Natural sign has been correctly rebuilt and recognized):\n[img[Glyph view of the fixed slur|images/slur-long-fixed.jpg]]
Debug staff line cleanup, with tangents, to avoid breaking glyphs as much as possible.\nThis is a tough area with important consequences, but the results in some cases are so strange that they deserve a careful analysis for improvement.
body {\n text-align: justify;\n}\nh1 {\n background: #ddd;\n font-size: 150%;\n}\nh2 {\n background: #fff;\n font-size: 120%;\n}\nh3, h4, h5 {\n background: [[ColorPalette::Background]];\n}\n\n/* To avoid display of editing data \n.subtitle {\n display: none;\n}\n*/\n\n.centered {\n text-align: center;\n}\n\n.big {\n font-size: 150%;\n}
Some glyphs, though recognized, are not yet translated to the score:\n*Breath marks,\n*Grace notes,\n*Staccato,\n*Ottava,\n*...\n\nUpdate:\n*All articulations (staccato, accent, tenuto, etc) are handled since V3.2c
Handling tuplets (triplets, etc...) of notes is still to be implemented\nDone for 3 and for 6 notes\nTo be improved to handle the case where all embraced notes are not part of the same beam (group)
Figures from a standard scanned sheet (//Dichterliebe-250.png//) 158 KB, 8 bits per pixel\n| !Picture| width| 2493|\n|~| height| 3217|\n|~| pixels| 8019981|\n|!hLag| runs| 38381|\n|~| sections| 6932|\n|~| glyphs| 479|\n|~| glyphIds| 479|\n|!vLag| runs| 36812|\n|~| sections| 3363|\n|~| glyphs| 954|\n|~| glyphIds| 1705|\n
Is it realistic to provide such "~UnDo" operation ?
Access to a private collection, as exposed by a getter method, now uses the Collections.unmodifiableCollection() method, to make sure that the collection is not modified. Adding or removing can only be done throught the dedicated methods, if any provided by the encapsulating class.\nThe modification has been done for the major collections and has resulted in no performance penalty.
Implement voices using slot occupation by chords/notes
*Time rules\n##Scope is a measure in a part\n##There is one start time per vertical slot\n##All chords aligned on the same vertical line belong to the same time slot (and thus share the same start time)\n##Start times are increasing from left to right slots\n*Voice rules\n##All chords linked by a beam group share the same voice\n##Two chords linked by a tie (same note, same pitch) share the same voice\n##If non-consistent ties arrive to the same chord, this chord must be split into 2 different smaller chords\n##Try to avoid jumping from one staff to another within the same voice\n##Try to avoid switching stem orientation within the same voice (weaker rule than previous one)\n\nDone with a rather comprehensive algorithm
Implement wedges (crescendo, decrescendo).