Thursday, December 31, 2009

Fixing dot to note matching algorithm.

//find dots which overlap with notes in stem and are not to the right of other dots being examined
//make sure we have the same number of dots as notes
//if we find more, discard dots which overlap with other stems (alternating between top and bottom)
//if we find less, defer

Wednesday, December 30, 2009

"Intellitrace" in VS2010 is a great time-saver when debugging exceptions.

Todos:
- Combine/include all ledgers
- If a note in a stem has dots, all notes must have dots. Must improve dot matching algorithm.

Tuesday, December 29, 2009

Have slacked off with notes over the past week. Fixed a bunch of stuff, moved a bunch of code across from old project and refactored. Yay.

Feeling pretty average. Could be to do with last night's beers, tradies schnitzel, bundy draughts and 2am maccas 'Agnes burger'. Ugh.


Using 'position' instead of tick when moving through score (where position is a double in terms of beats).

Current todos:
- Set start tempo and dynamics for score. Will hard code defaults for now (done).
- Link all stems in prev/next chain and move current stem prev/next (as in beam chains etc) to new properties (done).

Changing all elements back to black after parsing and (for now) colouring notes green when they play. Playing through score, but with no noteOffs yet.

More todos:
- try/catch block in logging code,
- try/catch/logging etc around ticks and input events

Friday, December 25, 2009

- Tempo changes contain one or more UI elements (usually text) and start/(maybe) end Stems.
- Tempo changes could be in linked list and use start/end ticks instead of stems.
- Got basic tempo stuff running (I think).
- Added base class for tempo and dynamic changes

Wednesday, December 23, 2009

- Need to fix bar numbers. Done.
- Did a quick bit of research around options for timers in C#. Currently using the windows multimedia timer which I think is still as good as it gets.
- Working on playing through score which requires the score and a timer. Trying to find the right balance between refactoring old code and writing shiny code.
- Not using a Chord object atm. Hopefully won't need it.
- Added a BarParsed class to move score parsing stuff up from Bar.
- Todo if two notes have the same pitch and position, don't play the earlier noteOff.

Tuesday, December 15, 2009

Tidied up namespaces in preparation for score playback stuff.

Sunday, December 13, 2009

Finished score navigation and changing displayed page count (basic for now). Need to fix a bug with initial display.

Saturday, December 12, 2009

My ScorePanel has FirstIndex and LastIndex for tracking which lines are displayed, and the display is changed by changing these values. We know that they are changed externally if they change outside of the rendering process.

If FirstIndex changes, we add lines from start to finish and if LastIndex changes we add them backwards (ie when turning back a line/page and we know the last line but not the first).

Moving to .Net 4.0 fixed an annoying bug that caused something to hang on to fonts, but caused a new exception (also to do with fonts, but perhaps is legit).

Removing Lines from ScorePanel Children triggers another render loop. Err.

Tuesday, December 8, 2009

It turns out that calling Measure() on a child control inside ArrangeOverride() can cause an infinite layout invalidation loop. I created my own Measure() method in the child controls which I call from MeasureOverride() and from ArrangeOverride() in the scorePanel. Extra layout loops went away.

Line Forward/back working. Page forward/back and Start/End should be easy.

Thursday, December 3, 2009

Binding FirstIndex/LastIndex DPs in ScorePanel to VM. They invalidate render if changed outside of render routine.

For some reason, scorePanel renders twice on load and I don't know what triggers the 2nd one (although external code callstack looks same as the 1st).

Tuesday, December 1, 2009

someDelegate.Invoke(); is about 1.3 times slower then a direct method call, and the same as calling the delegate itself.

dynamic blah = someDelegate; blah.Invoke(); is just under 10 times slower than method call, which is close enough for me (since a loop of 10,000,000 calls takes 770ms). ((dynamic)someDelegate).Invoke(); is marginally faster and is easier to use.

Delegate blah = someDelegate; blah .DynamicInvoke(); is about 550 times slower than a method call and doesn't add any value over using a dynamic.

It looks like I'll be using dynamics.


Tidied up some stuff. That should be enough tidying for now, back to page turning stuff.

Monday, November 30, 2009

Mucking around with delegates and dynamic methods. Trying to get some boilerplate code right before using it everywhere.

Need to test the performance of
Delegate.DynamicInvoke();
vs
dynamic blah = someDelegate;
blah.Invoke();
vs
someDelegate.Invoke();

Hopefully the 2nd option isn't much slower than the 3rd.

Sunday, November 29, 2009

Ballsed up usage of linked list for stems since I use them for stems linked by beams, not just all linked by position. Not linking stems outside of parsing yet. Fixed some shit.

Saturday, November 28, 2009

- Added buttons for navigating score. Need to actually make them work.
- I'll add functions to score panel, but hook buttons to commands in VM with try/catches etc.

Wednesday, November 25, 2009

Fixed a bunch of stuff and decreased parsing time. VS 2010 performance profiler is pretty nifty.

Next job is to add controls and functionality to turn pages and adjust page count.

Tuesday, November 24, 2009

Cleaning up last of refactoring. Trying to avoid infinite loop where Element looks to owner for a bar and the owner looks back to its element for a bar. Not quite sure how I want to handle this yet.

Monday, November 23, 2009

Fixed some bugs, found a problem with a certain font that I don't understand (used to work fine).

Need to check that tied notes are still working in Op 72 #1.

Cbf with proper notes tonight.

Sunday, November 22, 2009

My notes for today went away. Shouldn't this thing save drafts regularly?

Got line layout going using set page count and max line size to fit pages. I guess the user is better off with control over page count and margin sizes (between lines and between pages) than zoom level. A zoom level is required if (for example) the user has a wide screen but wants just one page. Hmm..

Page count could be main control with a zoom level from tiny up to that allowed by pages/screen (or turn off page count and just have as many pages as possible for current zoom level).

Saturday, November 21, 2009

- Line width could be based on zoom level (up to a max number of columns) or max zoom so as to fit on a fixed number of columns/pages. Will go with 2nd option first.
- MeasureOverride and ArrangeOverride really need to do much of the same stuff and it seems a bit silly to do it twice. For now I'll do it all in Arrange and have Measure just return the max available size. I guess I'll have to change this if the ScorePanel ever wants to be smaller than the maximum.
- ScoreLines shouldn't just stretch to fit since they have different widths. We pass available width in to line to get desired height, but the line might not use the whole available width. I guess the lines still need to use the zoom property.
- Padding between pages will be zoomed too.

Thursday, November 19, 2009

Going to assume that the set of line children are the same for all lines.

For now I will use the same margin above/below lines regardless of where they sit on the page (first, last or other).

'Rectangle' is a sealed class. What the fuck is wrong with letting someone derive from it? Fucking arseholes...

Got a panel to hold/measure/arrange all drawing panels/rectangles for a single line and a panel to build/measure/arrange collection of these panels. Placement and painting basics sorted.

Wednesday, November 18, 2009

The distances between scorelines in a pdf etc seems to be as much influenced by the number of lines on the page as the content of the lines.

I can lay out lines based on Y distance between staves, Y distance between lower/upper extremities or (maybe) min dist between lines where no elements overlap. I guess I'll need some combination of the above. (todo) For now I'll go with a simple algorithm.

Display thingies (lines, graphs) could be UIElements that can be used in XAML and bound to stuff. If the number of drawing elements are the same, increasing the UIElement couldn't hurt too much. LineGroups could derive from Panel.

Tuesday, November 17, 2009

Got some basic layout logic going for scorelines. The panel tells each line how big to be (based on zoom level), but doesn't allow the panel to respond. Ie it only works for scorelines and overlays might need more control. I might have to make a panel stack holder which contains scorelines and other children and queries them for sizing. I think I can implement this easily enough later.

Monday, November 16, 2009

Installed VS 2010 beta 2, looks pretty snazzy. Had to change target framework to 4.0 to fix an odd reference problem, but could've been something I'd done. Displaying keyboard shortcuts on context menus and pinning debug mouse over is great. The crashes aren't so great (but worth it).

- Setting ScoreLines on ScorePanel, got some parsed/packaged lines displaying (in a pile).
- Controls on a tab item get destroyed when the tab is deselected/hidden and recreated when it is reselected. All of my data lives in VMs so that should be cool.

Saturday, November 14, 2009

Took a good look at the 'Cinch' MVVM WPF framework. I got some ideas but will keep working with my own framework for now.

Got some basics of the edit view sorted.

Friday, November 13, 2009

Working on score display panel and score edit view simultaneously (to releave boredom really).

Edit view is more urgent really, but I'm not quite sure what it'll need yet. Score properties are a good start, but might warrant their own tab or something. I'll start with the score display (and associated page turn/display functions) and play/pause/stop/start stuff.

Installed MS Enterprise Library for logging.

Added action wrapper with exception handling and logging.

Need to tidy up MainVM and events.

Thursday, November 12, 2009

Cleaned up some stuff.

Going to make two main 'views': existing view for score parsing and new view for score editing/playback etc. All elements must be identified or discarded in parsing view (at this stage). The parsing view displays the score in pages as read in from XPS document. The edit view displays score in lines (dynamic pages) generated from parsing.

A score is not saved to a database until it is shifted to edit mode, and only data required for edit mode will be persisted. If the score is cleared from memory (ie closed), it can be opened again from the database for editing/playing but cannot go back to the parsing mode. This means that the score parsing must be done in one session. I'll move things from parsing mode to edit mode as required. I might not allow shifting back to parsing mode if it doesn't add much value and I can move important things to edit mode. I don't want to clutter the edit mode though... will see how it goes.

Objects loaded from the database will be superclasses of objects created during parsing to trim code and data not required during editing/playback.

The views will be based on separate VMs. The parsing VM must be retained in memory until the score is closed, and I might be able to display them simultaneously on separate tabs.

Just starting on edit mode VM and score display panel.

Wednesday, November 11, 2009

- Lines producing basic DrawingBrush. All child elements are individual drawings. I don't know how much this will affect performance (particularly for large scores).

Tuesday, November 10, 2009

Finished refactoring main objects, much happier. Midi generation seems to still work.

Monday, November 2, 2009

Cleaning up object model in preparation for post-data munge use. Trying some heavy use of generics and a granular inheritance hierarchy.

For example, I have a class:
public class DBObjectNodeEnum<P, T, C> : DBObjectNode<P, T>, ICollection<C> where T : DBObjectNode<P, T>

and Bar:
public class Bar : DBObjectNodeEnum
<ScoreLine, Bar, Stem>

which gives bars database CRUD, linked list node (next/prev bars etc) and children. I'll use this for Scores, ScoreLines, Bars, and Stems, DBObjectNode for Notes, and just inherit from IList for Staves and Chords. Maybe DBObjectNodeEnum for notes depending on how we polish voices.

I still want multiple inheritance in C#...


Next job after this is to generate scoreline drawing brushes.

Sunday, November 1, 2009

Finished score parsing for now. I'm sure that new scores will cause problems, but I'll fix them when it happens. The next major goal is to wrap up the data in a database and display it nicely. Since I have the data in memory I can skip the wrapping step for now.

The current display uses one surface per page with all surfaces displayed in a big scrolling thing (a grid of rectangles with DrawingBrushes). I guess I need to generate drawingBrushes for individual lines. I can keep the grid and rectangles and add/remove rects as required. I'll chuck a scrollbar somewhere bound to zoom.

I'm currently setting the size of the score by setting the width and height of the rects and letting the brush fill to fit. I guess the best solution is a custom layout panel. Alternatively I can add brushes to a group with translateTransforms and scale the whole thing. Going to start with custom panel.

Saturday, October 31, 2009

- Picking up tied note across lines in rev etude.

Sunday, October 25, 2009

- Rev etude missed tie crossing line from bar 77 to 78.
- If a new element type is added to the db (or something is explicitly set to a type), any templates in the db that conflict must be removed.
- Fixed a bug that magically appeared in finding ledgers to match stems to staves. I don't know how it ever worked before...
- We'll be able to give ties a different colour to phrases and slurs which will make it much easier for end users trying to read the music.
- Fixed bug with matching dots to notes that are on left side of upside-down stem.
- Rules for end note of tie seem the same as start note but with X reversed.
- Finding ties that don't cross over lines. Not yet using for note lengths or silencing tied bits. I don't know if ties that cross lines have same Y value for both ends of both curves. Pic with magenta-y tie goodness.


- Ties that cross lines might work now but I don't have an example to test it on yet.
- Need to ignore ties which actually have notes of same pitch inbetween start and end notes. Also need to ignore ties where end note has an accidental. Done.
- Need to incorporate ties into midi shit.
- Tied notes violate the rule that all notes in a stem have the same length.
- I could crosscheck the tied note info with the voice building stuff (todo later).
- Added tied note info to midi builder.
- Note offs need to be set a tick early to prevent them from interfering with note ons with same pitch and tick.

Saturday, October 24, 2009

- Starting on non-overlapping stems in chords issue. It should only be a problem when a new voice starts. If a voice stops mid bar it might indicate a problem too.
- Each stem in a 'chord' much be a different voice. In the two examples in Rev Etude, both 'misplaced' stems start new voices.
- Done. Here's a pic of the example in the Rev Etude. The dotted minim caused the problem.

- Starting on finding ties (such as those in blue in the pic above). I think ties/slurs/phrases are being found quite well already but not categorised yet.
- Ties apply to individual notes, not stems. Curve direction of tie doesn't relate to stem direction but does matter to note position relative to stem.
- Tie will overlap on X axis unless tie curves up in the middle and stem is upright (usually). If start or maybe end note are not the top/bottom note in the stem the tie may be moved to the side.
- Tie ends must have same Y.

Friday, October 23, 2009

- Fixed glyph duplication problem and subsequent key sig detection error.

Thursday, October 22, 2009

- Current issues to fix in Rev Etude midi generation:
  • Ignore stem above first line in tempo indicator, (done)
  • Bar crossing two lines, (done)
  • Key signature detection not picking up all elements. Found that some glyph runs are duplicated which could be related. Duplicated shouldn't be too hard to fix (tomorrow).
  • Tied notes (including ties across lines :/ ),
  • Stems in chords which don't overlap on X axis are interpreted as in separate chords

- Stems in chords will not overlap on X only if they overlap on Y.
- Stems may not have the same note value.
- Should check X position of stem before appending to voice. Position can't be absolute in bar but can be relative to previous stems and voice lengths.
- Can use chained stems in other voices as guide for where voices are up to in bar.
- Stems can't be new voice starting off beat.

Tuesday, October 20, 2009

- Using tuplet bracket info. I think that bit is finished.
- Some problems where stems in same chord don't overlap (bars 57 and 80 in Rev Etude). This results in the bar being too long. Perhaps I can use the fact that the stems are obviously in the wrong place relative to stems in other voices.
- Bar spanning two lines causing problem but shouldn't be a major issue to fix.

Monday, October 19, 2009

- Finding tuplet brackets (in at least one score anyway). For a change of pace, here's a pic. The light orange things are the brackets and start/end stems, and red-orange stems are the nearest to middle stems in brackets. The rest in the 2nd triplet gets picked up later. The voice builder isn't actually using the brackets yet; tomorrow maybe.



Sunday, October 18, 2009

- Looking for side bits of tuplet brackets to determine whether tuplet is above or below bracket.
- Fixed bug with element intersection detection.
- Finding tuplet brackets but will need a little more work to increase confidence. Finding first stem for each bracket.
- I think I can reliably find the first and last stems in the bracket and if the bracket is >= 3, the closest middle stem to the tuplet count. Hopefully all stems in the tuplet will be beamed to one of these three.

Friday, October 16, 2009

- Trying to hunt down stems belonging to tuplet brackets

Tuesday, October 13, 2009

- Working on finding tuplet brackets for tuplets in which not all elements are beamed. There doesn't seem to be any other reliable method to join such elements. Using tuplet count glyph, relative positions of possible bracket bits on either side of tuplet count, gradients of lines within bracket bits etc.
- Maybe I can assume that tuplets that start or end with disconnected stems or rests will always have the count written in. I'm not sure that searching for a tuplet count before parsing the notes is best, particularly when the symbols used to indicate the stems included are quite arbitrary (if given at all) and have varying widths and orientations even within a score. Also, if the first stem of a tuplet is disconnected, we have no clue that we're working with a tuplet and the count is written in under the middle of the tuplet, not the first stem.
- I'll start by looking at how the bars are resolving in the Rev Etude. Hopefully this will be the last task before working on exporting the music.

Monday, October 12, 2009

- Fixed some timing bugs.
- Having problems with some tuplets in Revolutionary Etude where some stems aren't attached with beams or tuplet starts with rest (such as in bars 55 and 62 of my copy). The bar lengths shouldn't resolve, and there are tuplet numbers written in which might help.

Tuesday, October 6, 2009

- MIDI generated for Op72 #1 now has no pitch or timing errors, and only one warning which is due to an error in the score (a minim that should be a crotchet).

Sunday, October 4, 2009

I've been a bit slack with keeping notes for the last couple of days.

- Working on producing midi file. I got my units of measurement a little mixed up (beats vs whole notes) which made for some interesting midi files, and forgot to use tuplet compression when calculating note lengths.
- Note lengths and positions now looking pretty good, but note pitches are a little bit shithouse.
- Fixed note pitch algorithm. It seems that bars without explicit key sigs think they're CMajor. That's not good. Fixed.
- All note pitches seem good now. One bar in Op72 #1 is failing miserably, and there is no use of pedals, 8vas, ties or grace notes yet.
- Not handling bars that cross lines... er
- Ran Revolutionary Etude through. Lots of little midi errors (bars too long/short etc), but overall pretty good so far.

Sunday, September 27, 2009

- Finding note pitches without accidentals/key sigs.
- Linking accidentals to primary notes.
- Finding all note pitches without applying 8vas/8vbs etc.
- Need to calculate note timings/positions in midi. Grace notes can wait coz I cbf tonight.
- Setting note positions in terms of whole notes relative to parent bars. I should now have note pitches, lengths and start ticks for most cases.
- Checking if ledgers intersect with grace notes will probably fail if note is in space. Er.
- There are seven half spaces in an octave on the score (seven major keys in octave) but twelve midi pitches (accidentals). Makes calculating the pitch a little messy. I'll need to store both half space count (from stave bottom) and midi pitch (where middle C = 60).
- Now storing half space count.

Saturday, September 26, 2009

- Starting on finding pitch of notes and accidentals not in key sigs. Requires a little more work on ledgers.
- Finding/grouping all ledgers between staves and connecting them to stems/staves/bars, but not yet finding ledgers at top and bottom of line.
- Finding all ledgers. It looks like some ledgers are duplicated and should be removed (todo).
- Starting to match accidentals to notes. An accidental (not in a key signature) will reference its primary note, but multiple notes in a bar may reference an accidental.
- That will be easier after I've found natural note pitches. Starting that first.

Or better yet, going out.

Friday, September 25, 2009

- Finding key signatures.
- How do I find a key change to C major from something else?
- I should add all ambiguous element matches to a list and rerun them after everything else has run so that the user can process them all in one go.

Wednesday, September 23, 2009

- Small notes are likely to be grace notes if the bar voices resolve without them.
- I think it's fair to assume that all staves within a line will have the same key signature changes. If signatures across staves match there's a decent chance they're correct.
- Regular accidentals can be very close to key sig accidentals. I guess there's only 14 well defined key sigs to worry about (multiplied by two clefs that I care about), and they grow in a simple pattern anyway. I'll just check that the accidentals at the start of a bar match this pattern.
- Finding the pitch value of a flat is a little harder than I thought. Next time.

Tuesday, September 22, 2009

- Finding rests within beam runs. Not yet handling rests that are part of a tuplet but are at the start or end.
- Throwing assert if a voice disappears mid bar (but on a beat) without a rest at the start of the next beat.
- Starting on grace notes. For now I just need to match them up to owning stems. Need to handle beamed grace notes, grace notes that appear at the end of a line (attached to note on next line) and grace notes that appear twice (end of line and start of next line).
- It'd be useful to have note pitches for this. I might start that now instead.
- Finding clefs. Clefs used to be associated with notes. I guess that still makes sense. I'll associate them with staves and all stems played immediately after clef change.
- I'll only associate them after voices are done, so it'll be a slow(ish) search each time before that (done, not too slow).

Monday, September 21, 2009

- Now finding tuplets other than triplets that are numbered. I'll need to account for series of tuplets where only the first is numbered (ie 7 played in 6 etc).
- Now looking for number on all suspected tuplets by default (even triplets).
- Need to handle rests within beam runs. Position of rest between stems (to what extent?), extra wide gab between stems around rest and resolution of time compression might be enough to confirm a rest is in a beam run.
- Need to work out how to discern between grace notes and notes which are small just for fun.
- Need to handle beams that cross over bars (ugh).

Sunday, September 20, 2009

- Matching dots to notes.
- Voices need to start and end on beats, and can be between one beat and one bar long.
- Refactoring beams a little to make finding note length a little easier.
- Need to disregard whole bar rests.
- Need to associate quaver/semiquaver etc tails with stems.
- Now parsing voices of first line of Schubert Op90 #1 in full.
- Will start on Chopin Op72 #1 with tuplets (lots of triplets and a few odd ones).
- todo: Notes that cannot be connected to staves are probably garbage (such as notes shown in the tempo thingy at the start of the score).
- Notes in a tuplet aren't always of the same length.

My feet are cold.

- Now parsing voices of first page of Chopin Op72 #1.
- Who the fuck puts a dot for a dotted note on a line in the space below the line? Ugh. I think it only happens on select upside-down stems.
- Parsing two pages of Chopin Op72 #1, now working on odd tuplets. Would like to tackle simple ornaments and grace notes next.

Saturday, September 19, 2009

- All notes and stems now linked to staves.
- Need to do the same for rests. Very fews rests not on a stave, but those that aren't don't have ledgers.
- It's picking up some partial beams as rests :/. Fixed by including semibreve and minim rests in beam search.
- Matching rests that intersect with staves, will handle other rests later.
- Will try to find voices. Main assumption is that overlapping stems (on X axis) are in different voices. Overlapping beams are different voices and all stems connected by beams are in the same voice. A stem can be in only one voice but a note can be on multiple stems.
- Need to filter out grace notes.
- Need to associate dots with notes. Ties can wait.
- Voices are not per stave, they can traverse staves.
- Need to include rests within beam runs.

Tuesday, September 15, 2009

- Continuing to find stave for stems. Going to find ledger lines moving from stave outwards until one intersects with note or none are found. Ledgers must be correct distance apart, thin, centred about stem (kinda).

Monday, September 14, 2009

- Made some progress with associating notes/stems with staves.

Saturday, September 12, 2009

- Adding time signatures to bars. Looking for commonTime elements or pairs of glyphRuns containing only numerical characters.
- Nearly all elements in a line must belong to a bar and a stave (including time signatures). Trying to find a nice way to represent this.
- Deciding to make 'get' methods [like public TimeSig GetTimeSig(Stave stave)] throw exceptions if value isn't found rather than returning null.
- Need a method to return the full real string from a Glyphs element. Fiddly.
- todo Need to combine bar lines that actually make up one bar (double bar line etc).
- todo Need to reinstate mass update of chars.
- Got time signatures sorted out (I think).
- Beams aren't always divided into beats as nicely as I'd hoped, but I guess I'd have to make it work for outlying cases anyway so no big loss.
- Time to associate stems with staves.

Wednesday, September 9, 2009

- Going to add all notes to stems, and some stems are implicit with only one note (ie semibreves).
- I'll then need to work out time signatures and beats before I can begin on voices.

Monday, September 7, 2009

I think I figured out something important while trying to sleep last night.. I don't want to put notes in chords until after voices are done, and chords are only an afterthought for other stuff further down the track.

Notes are grouped on stems etc for a reason, and if two notes overlap on the x axis without being on the same stem, they mustn't be in the same voice. Notes not on stems (semibreve and longer) aren't going to be shorter than a beat, and beats are more important than bars. Since semibreves etc are at least a beat long and (I assume) always on the start of a beat, it won't matter if they are treated as separate voices. Rests might be a bit difficult...

Sunday, September 6, 2009

- If two notes are in the same chord, one pitch apart and on different stems, the stems almost line up but the notes are on the outsides of the two stems and don't overlap at all on the x axis. Will look for stems that almost line up with notes that go in opposite directions and have notes that overlap on the y axis.
- Added left and right brackets as element types (rather than just regular characters).
- Saving character templates after glyphs are confirmed.
- Fucked around for a few hours looking at some anomalies in the detection of characters. I think it's sorted now... maybe.
- It looks like semibreves are aligned with other notes in chords by their left side, not their centre.
- Notes in a chord seem to be left aligned unless a stem is shifted to avoid overlap (which is a pain in the arse when combined with tuplets etc). I think the lower note/stem is always shifted right regardless of stem directions etc.
- Will sort notes/stems so they are added to bars from left to right. Working better.
- Grouping notes into chords would be easier if I knew their pitches.
- Handling notes/stems shifted because of other (disconnected) notes/stems in same chord. It's currently pretty accurate, but since in some places it can even be difficult to figure out manually without looking at previous note lengths/voices, I may have to work out voices as notes are added to bars to ensure chord groupings are correct. Gonna be hard :/
- I think I'll work out voices after grouping into chords and see how difficult it might be to merge them later.

Saturday, September 5, 2009

- Added some boilerplate code for sorting/enumerating/adding/removing lines/bars/chords/stems/notes.
- Lines contain set of elements which (mostly) have known types, but not wrapping objects (Notes etc). I'm not keen to go breaking existing code, so I'll let the lines hunt down wrappers the long way.
- I think I need to get rid of distinction between grace note and normal note types for now since normal notes in long tuplets can be as small as grace notes. Code can try to figure it out after detection is done.
- Todo (later): since a positive template for one element type effectively acts as a negative template for all other types, I should store character templates when user confirms glyph set (but not actually try to match those characters afterwards).
- A chord is actually comprised of a set of stems (where stems of breves etc are implied, and a note can have two stems). I'm not sure what the implications of this are yet, but I'll definitely be using stems (and stem associations via beams) for finding voices. I'll pass stems to bars first, then orphaned notes, then rests.
- Maybe I need a panel that lists the main steps in the whole score parsing process that shows the current step. If non-modal user interaction is required (such as confirming Paths), they could click a button on this panel to confirm that a step is complete. It would require all of the current stuff to happen on a background thread with invokes to UI thread, but I should probably do that anyway.
- Adding notes to chords in bars. Not yet handling grace notes or rests.
- Going to keep all elements in main bits array.
- Improved performance of show/hide all element types.
- Created Bar object (which holds an existing element with type of 'bar'). Will pass in notes to be grouped into chords tomorrow. Based on experience, I'm not at all concerned about redundant data structures or causing the GC to take an extra ms to do its job. Chewing cpu cycles with derived object properties rather than storing values (such as a note's clef) for efficiency also looks good.

Thursday, September 3, 2009

- Not quite sure what to start next. I'll leave detection of hairpins and annoyances such as repeats, 8vas and ornament stave thingies until later.
- Dumping all detection templates to disk as bitmaps for debugging.

Tuesday, September 1, 2009

- Last night's problem fixed. Algorithm was fine, but a break statement snuck it's way in somewhere it shouldn't have...
- I'll make pedals always belong to the line above just in case. Done.
- Will also make phrase marks belong to the line from which they 'bulge' away. Done.
- I think I need two kinds of 'ignore' buttons on the element type form: ignore now and ignore forever. I also might need to make a set of temporarily templates for ignored elements so if you ignore one element, it ignores all elements that look similar.
- I suppose it's time to start putting notes in chords, finding time/key signatures etc.

Monday, August 31, 2009

- Saving point collection of each element as a property on the element, solving storage and array tracking headaches.
- Finding element without known line closest to a known element proving quite difficult to do in an efficient manner. High risk of getting stuck on local maxima.
- Algorithm almost works... bed time

Sunday, August 30, 2009

- Lines now change their colour (bars, lines in staves, brace etc).
- Grouping stuff that intersects with line staves.
- Need to group things which lie outside of lines but are associated with things inside lines (notes/beams with stems etc). Probably a good time to refine my object model a little.
- Chaining through stems and then beams/notes works well.
- Will assume that anything that intersects with something now in a line is also in that line. Works pretty well..
- Trying to group left-overs by how close they are to other stuff already grouped. This will need to be an iterative operation starting with the best candidates and progressively working outwards as things are grouped.
- Grouping stuff at top and bottom of pages.
- How do I measure the minimum distance between two weird shapes? It is possible to convert a StreamGeometry to a series of points (in a long string) which somewhat match its shape. I guess I'll then have to do a lot of comparisons between points of shapes. Inefficient, but I care more about accuracy for the moment.
- Actually, it's just too slow fkn. Perhaps I'll use eight points from an elipse that fits within the bounds of an element. I'll use higher accuracy for things which appear to be phrase marks.
- Turns out google calculator defaults to radians for trigonometry... I'd forgotten about those.
- Using a few points from a fitted elipse is fast enough. Will (hopefully) finish grouping tomorrow.

Saturday, August 29, 2009

Had perhaps one too many beers... sometimes makes my code more interesting.

- Setting phrase types (not yet categorising into phrase, slur or tie though).
- Ready to divide stuff into lines. Will colour elements based on line (alternating colours for lines) and user can click on elements to switch them between line above or below.
- Fixed small misalignment of split glyph runs. Now to fix big misalignments.. (I think due to substring starting with or after space).
- Looks like all glyph runs are being split and replaced correctly.
- I might need to do something special for dots since they can be characters in strings or a note dot etc. Done.
- Todo: improve element click detection (later).
- Found a couple of beams between grace note stems not being detected properly. Grace noteheads are detected correctly, but the first stem isn't. Fixed, apparently stems can be shorter than I anticipated (less than 2 spaces high).
- Todo: if a Path is set as a notehead by the user, rerun stem/beam detection (later).
- Time to finish detection of phrases etc and group stuff into lines (but I'm not sure which to do first..).
- Actually, time for a chat over beers.

Friday, August 28, 2009

- It turns out that the geometry collection of the geometry of a glyph run may not be of the same length as the glyph run string since spaces (etc) aren't represented. Ugh. For now I'll assume that glyphs not in my main glyph list (such as spaces) aren't in the geometry. Seems to be working so far.
- Coords of glyph geometries not quite lining up properly yet...
- I think I found the cause, bed time now.

Thursday, August 27, 2009

- Displaying character being processed (as well as highlighting full string on score).
- Finding it difficult to debug some behaviour which might actually be correct due to the matching data changing each run and the sheer volume of information processing. I think it's working ok..

Wednesday, August 26, 2009

- Working on splitting all string instances before assigning their purposes.
- Need to display character being processed in long string when prompting user for type.

Sunday, August 23, 2009

- Fixed bug causing grace note slash detection to fail in Op72 #1. Need to split all string instances and do something about dots (which can be musical notation or in regular text).

Saturday, August 22, 2009

- Found width and height of glyph within run.
- Attempting to break up glyph run into separate elements. Finding the absolute position of glyphs within run is probably the main problem.
- The Geometry of a GlyphRun is a GeometryGroup, and each child Geometry represents a character with a distinct bounds Rect. I can create a single char GlyphRun copying properties from the original run, then set its XY offset to the difference between its Geometry Location and the Location of the Geometry of the original char.
- Looks like it works. If a glyph is not a char, all glyph runs containing that glyph need to be broken up into two or three pieces. The original Element needs to be removed and replacement Elements added. Done, but stuff isn't quite working right..
- Need to dump template bitmaps to disk to debug, split all glyph strings with positive matches and (possibly related) work out why grace note slash is detected as grace tail.

Friday, August 21, 2009

- Moved glyph list to user control and using on main score view and in modal dialog. Putting dialog down left side of main window. It's not immediately obvious that it is there and waiting for the user, but they'll learn...
- Glyphs that only appear in multi-char strings aren't going through image parsing since it should be a safe assumption that they are just characters rather than music elements. Bad assumption :/. I'll detect all glyphs and perhaps be a little more strict on glyphs that only appear in multi-char glyph runs.
- Saving template for single glyph in run turning out to be a bit of a bastard. User can't specify which char they want within a run and it's hard to get specific size of glyph in glyph run. Good job for tomorrow.

Thursday, August 20, 2009

- Working on breaking glyph runs (strings) of musical elements which are longer than one character into single char glyph runs. For example, in some instances a note and its dot or a clef and the key signature are grouped in a single glyph run. They need to be separate elements.
- After glyphs are matched, the user will be prompted to confirm that all glyphs are correct. After confirmation, glyph runs will be broken down and the rest of the score detection will begin.
- The prompt window could be modal if I use the current glyph type list view thingy inside a modal dialog. The user doesn't need to interact directly with the score and the operation shouldn't take long.

Wednesday, August 19, 2009

- Fixed detection of one beam. It turns out that ordering potential beams by their bounding rectangle Y position descending (bottom to top) is just different enough from ordering by bounding rect bottom Y desc to bugger my algorithm.
- Another 2.5 hours of debugging later, beams are all good including joins of broken beams under/over rests.

Monday, August 17, 2009

- Improved bar finding/joining algorithm. Some duplicated composite elements were surviving and new algorithm ignored those that were bars.
- Tracked down and patched up duplicate/composite culling hole (requires multiple passes scattered around other processing jobs which get increasingly strict).
- Started debugging couple of broken bars in Op90 (one to do with rest in beam run). Probably due to tolerances out a bit.
- Working on allowing user to select score elements and set types.
- Kinda fixed bringIntoView problem by requesting a larger rectangle (padding). Perhaps I could fix it properly if offsets are the cause of the problem.
- Generics plus events can do some very cool stuff.
- Need to be able to remove template if user makes a mistake. Maybe later. (Did a little bit now).
- Not finding bars in Minute Waltz.
- Setting glyph type changes type of all glyphs.
- Glyphs not in single length strings not getting matched. Matching done on element instance rather than glyph. Could be done on single glyph but would need to extract glyph size from string.
- Made a mistake with templates, app handled it well.
- User can now select score elements and set types. Refactored detection stuff further.
- Need to rationalise font storage.

Saturday, August 15, 2009

Mmm, chocolate for breakfast.

- Continuing on with multiple templates.
- Finished some good refactoring of matching algorithms including multiple passes.
- Improved error reporting of database actions.
- Fucken VS holding on to stale data when showing tables. Fuck.
- Multiple positive templates done.
- Most element types rebuilt.

Way past lunch time..

- Will use negative templates by removing all positive matches of same type that do not have significantly better match scores. Done.
- Detection now getting very good.
- Some unknown paths on Etude Rev and a couple of dodgy beams to check. Need to allow user to select paths from score and set type.

Time to go drink beer.
- Finding curve (phrase etc) orientation by finding line between start and end points and the average of the other points in the curve. Orientation is given by whether average point is above or below line (assuming line is never vertical). Done.
- Still a bit difficult to confidently mark curve as phrase etc without matching it to notes. Difficult to match it to notes without things grouped into lines and notes in chords.
- Need option to ignore an instance of a glyph without ignoring all glyphs of that type.
- Perhaps it's time to break things into lines. Gonna be a bitch.
- Having the user confirm that element types are correct before breaking into lines will help. Most element types found above or below lines have enough info to determine which line they belong to (as opposed to unknown shapes).
- Discovered that semibreve and minim rests can be by themselves with ledger line built in... another couple of new types.
- Finishing type detection would make line division easier and needs to be done.. perhaps I'll just do that... ugh.
- Multiple positive/negative templates means database breakage. Seems a good place to start.
- Renaming columns in SqlCe database a bastard. ElementTemplate table and mapped class created, ElementType table updated.
- Do I include min/max sizes for types in element type or each template for a type? Each template I think..
- Tweaked database reading/writing. Column names are retrieved for a table and select/insert/update queries generated using column names and reflection. Class properties must match column names for it to work (probably a good thing). Statements are cached for each class, but parameters must be get/set using reflection each time. Performance is fine for now, could be improved later.
- Adding multiple templates per type into the mix is a bit of work... bed time.

Thursday, August 13, 2009

- If an element type hasn't been defined, the user isn't prompted unless it is a similar size to existing types (a side effect from another process). We don't want to prompt the user for everything because of slurs etc. A second pass after beams/slurs etc are detected could work.
- A new pass for each new element should result in the minimum number of user prompts.
- Detecting phrases etc underway. Checking that geometry contains a curve (maybe no line) and that start point equals end point. Yet to check that element spans a couple of notes or a note near stave end. Not having elements grouped by line may make this difficult, but finding curve orientation and having note stem direction will help.
- Full beam pieces that aren't the top/bottom beam are being detected as half beams. Fixed; rejigged beam finding algorithm, handling upright and upside-down stems in separate passes. Beam top must be very close to top of upright stem (reverse for upside down stems) and additional beam pieces (semiquavers etc) are compared to previously found pieces. This requires that stems are processed left to right and beams top to bottom for upright stems, bottom to top for upside down stems. Beam detection solid, not interferring with semibreve/minim rest detection.
- Beam section between two stems is broken in two pieces below rest within set of beamed notes. Now detecting and joining pieces. It might be broken if there are consecutive rests between two stems in a beam.

Tuesday, August 11, 2009

- Starting to fix fill on duplicated elements (my algorithm to combine elements must be dodgy).
- Turns out that some elements have pen objects that shouldn't (and possibly fill objects too). Fixed. Score looks nicer and some detection anomalies are now fixed, but I might need to reset detection templates.
- Some combined elements now not filled properly. Fixed.
- Beam detection failing in all cases in one score. Looks like it probably never worked, beam pieces have five points in path rather than four. Fortunately two points are the same so a fix should be easy enough. Fixed. Problem included some scores placing beams on top of stems and others placing beams between stems. Ugh.

Monday, August 10, 2009

New todos:
- Show image of selected element separately from score when selection looks ambiguous,
- Join beam pieces (maybe can assume a beam section has no more than two pieces, but it could have more if there are consecutive rests within a beamed run),
- Some full beams are being detected as short beams.


- Stems on minims not found. Fixed.
- We have already detected staves before searching for most other stuff including beams and semibreve/minim rests. I'll make detection check that a rest hangs off or sits on a stave line before declaring it a rest. Done (and not prompting user for new element type fkn).

Sunday, August 9, 2009

More todos:
- Zoom and next/prev page controls.
- Top left and bottom right almost-transparent dots to fix min size and position of score.
- Showing/hiding individual element types.
- Need to allow user to easily select elements. Could check if user clicks within an element using high cost intersection and if not, check within bounding box, then within inflated bounding box. Elements should be ordered smallest to largest for bounding box test.
- Stems on minims not being found.. detection order back the front.
- Finding lots of semiquaver beams as semibreve rests. Second page of Op 72 has runs of demisemiquavers causing some beam detection problems.

Home time.

Saturday, August 8, 2009

Current todos:
- Visibility filter for element types,
- Multiple positive templates,
- Negative templates,
- Fix fill on some elements, particularly phrases, slurs and ties. The fill currently gets a bit mangled when combining duplicate elements,
- Fix 'bringIntoView',
- If user changes character value by certain amount (288 - ascii value), prompt if they want to do so for the rest of the font,
- 'Character' button on ElementTypeDialog. Maybe colour ok and 'ok no save' buttons red and green,
- Lunch,
- Save score data (either after auto parsing has finished or when user has finished bulk of changes.. probably the former),
- Break score up into lines,
- Store fonts in db,
- Start adding musical context to elements.

- Lunch eaten.
- Starting work on filter. Hijacking Glyph type list since it's now replaced by the ElementTypeDialog. GlyphTypeHolder now has a Show bool.
- Added Show/Hide All checkbox, updated GlyphTypeHolder DataTemplate, hooked up bindings.

Friday, August 7, 2009

- Continuing on with new element type dialog. Done.
- Will start element type filter to show/hide all elements of particular types. Also need to start saving negative templates and multiple positive templates.

My feet are cold.

Friday, July 31, 2009

- Starting dialog for saving new templates.
- Fuck it; it's Friday

Tuesday, July 28, 2009

- Probably need to save false positive images/templates to improve detection over time.
- Manual change of glyph type now saves (if the type exists in db).
- Ready to start dialog for new glyph type properties

Monday, July 27, 2009

No cold, hangover, birthdays or dates tonight. Yay..

- Going with a new dialog to create and save new element types.
- Using DetectingElement modal dialog for user glyph matches is a little clumsy but is useful because of existing save/no save buttons (which I worked out after finishing a non-modal way to set element types which is too unsafe regarding database updates).

Wednesday, July 22, 2009

- Moved CurrentGlyph and CurrentGlyphType properties down to ScoreParser from VM. When the CurrentGlyph changes I can find an instance and set DetectingElement which will highlight the instance on the score. Cool.
- Mostly works; I need to refactor code for saving stuff. Perhaps I can pop up a dialog for details when saving an element type for the first time (name, mustIntersect etc).
- There's a problem with the FrameworkElement.BringIntoView() method in that it doesn't always bring things into view. It may have something to do with the Y offset of the parent object, but this is an annoyance I don't need.. :/

Tuesday, July 21, 2009

It seems that the Sunday hangover was as much thanks to a cold or flu as grog.

- I'll set glyph types on all glyph instances and just update them as necessary when the user makes corrections.
- Adding a few more element types to database. The range of types is getting a bit broad (such as 'tail5topGraceSlash' for the flag/tail of an upright acciaccatura).
-
Need to add a button to confirm match but not update detection params in db. Done.
- Need to do something clever when user manually sets glyph type. Must highlight instance of glyph on score and on change, update db. Might need a checkbox to toggle db updating.

Sunday, July 19, 2009

Hangover level at about 3.

- Currently have spinny magenta rectangle around selected score element, but sometimes it can be off the page.
- Score now scrolls to centre selected element.
- Continuing on with problem of music glyphs incorrectly grouped in strings and ballsing up my matching.

- Adding a big fat button for false positives on garbage elements. Done.
- Need to colour found glyphs to figure out what's going on.
- Err.. glyphs in strings doesn't matter since I'm matching each glyph type, not instances of glyphs. Just need to apply match results to glyph instances (and can break up strings where necessary).
- Breaking up glyph runs (strings) might be hard since the positioning of each character is relative to previous chars and is based on funky typography/font stuff.
- Need to allow user to adjust glyph types before setting types of all instances

Hangover still at about 3.

Wednesday, July 15, 2009

- Starting to matching glyph types.
- Only going to match glyphs that only appear in single char strings. Done.
- Need to filter out glyphs which never appear on score. Done.. I think.
- Having a problem with glyphs in glyph runs that really shouldn't be (like bass clef followed by key signature accidentals being treated as a single entity). I could check all glyphs that appear in at least one single char string rather than in only single char strings. User can still override poor matches.

Tuesday, July 14, 2009

- Clearing selection rectangle.
- Need to hook up Element type dialog to element being processed. Done.
- Updating element type size info in database when a type is confirmed, but there's no real safeguard against outlying elements ruining data.
- Next up: guessing glyph types and verifying with user (rather than just paths).

Monday, July 13, 2009

- Trying to place some kind of blindingly obvious effect around a score element when it is selected. This is a little difficult because the elements are all bits of a larger drawing for efficiency, and the larger drawing is translated and scaled automatically.
- Individual drawings can be animated so long as they're not frozen. I can create a new drawing (such as a rectangle) and add it to the selected score element's parent which takes care of coordinate translation to place it over/around the element. I can then animate the drawing; yay for spinning rectangles.
- First attempt resulted in a cluster of little red rectangles orbiting around the screen with the score jumping and spinning everywhere to stay out of the way. Not quite the desired result... The rectangle rotation origin needs to be fixed to the centre of itself, not the top left corner of the canvas. Setting the RotateTransform CenterX and CenterY to the centre point of the element bounds fixed it.
- Spinny red rectangles on selected element on score finished.
- Need to remove rectangles when not in use. They currently sit around and spin forever after I lose reference to them.
- Now holding on to selection rectangle and its parent, will be easy to remove.

Sunday, July 12, 2009

Hello world

So who is this blog for? I'm not really sure yet, but for now I guess it's mainly for me. It can be motivating to look over your shoulder from time to time and see how far you've come. I plan to post snippets of what I'm working on as I trudge on towards the completion of my software dev project.

Maybe someone will find my posts interesting; if you don't know who I am or what I'm working on, probably not so much.

I'll try to keep main tasks in bold, followed by the details, plans and ideas (random shite).

- Currently working on parsing of scores in .xps format. Element identification is pretty good.
- I need a way to bubble events up to UI so user can confirm dodgy detection. If a element gets a poor detection ranking but user confirms it, templates and error margins should be adjusted.
- Routed events look promising but seem tied to DependencyObjects. Also difficult to hook routed events to model objects nicely.
- Could just use CLR events on model objects, but kind of need handling at VM layer and view layer. In this case, UI will place adorner around the element on the score (retaining context), select element type in currently displayed list (easy), user changes type if necessary and hits a big ok button (or presses enter).
- Parser must set a CurrentElement property. I'll make a new element type list so as to not interfere with shit that currently works. UI can bind straight through to parser.
- How will detection pause while waiting for user? Really needs to wait on modal dialog :/
- View can handle propertyChanged event for CurrentElement and throw up dialog. Dialog can live on the far left side of the screen.
- Ugh, the score doesn't get drawn to the screen until the parser has finished doing it's thing. Need to break down parsing and drawing routines, draw score to screen, hook up events in VM, then start parsing.
- Parsing/drawing order rejigged
- "Cannot perform this operation while dispatcher processing is suspended." In other words, I can't show a dialog until after the main score window has rendered. Shit. Starting parsing from score panel loaded event works.
- Displaying set of possible element types (quaver, quaver tail top, quaver rest etc etc) in dialog window when user confirmation is required.
- Elements are displayed as Drawing objects which don't have automatic "bring into view" method. Gonna have to place selection adorner manually.
- Looks like I did it manually last time anyway, easy enough to adjust.
- Or not. Score is drawn as drawing brush which gets stretched. Will have to work out translated point of a drawing within the brush.