[libgtkmusic] API refactoring, some bug fixes and sample code.



commit 867912a31072201db9c23383bf780b9c27df151b
Author: Leandro Resende Mattioli <leandro mattioli gmail com>
Date:   Mon Dec 10 14:26:58 2018 -0200

    API refactoring, some bug fixes and sample code.
    
     * refactored some properties to underline separated words,
       instead of camelCase (but only minor version was incremented)
     * added sample code (minimal example and fluidsynth based virtual piano)
     * updated README and build instructions

 README => README.md    |   0
 meson.build            |   7 +-
 python/example.py      |  22 ++++++
 python/virtualpiano.py |  47 ++++++++++++
 src/GuitarWidget.vala  | 189 ++++++++++++++++++++++++-------------------------
 src/MusicalNotes.vala  |  16 ++---
 src/PianoWidget.vala   | 170 +++++++++++++++++++++++++++-----------------
 test/TestsGuitar.vala  |   8 +--
 8 files changed, 284 insertions(+), 175 deletions(-)
---
diff --git a/README b/README.md
similarity index 100%
rename from README
rename to README.md
diff --git a/meson.build b/meson.build
index c38e1b3..5e7c517 100644
--- a/meson.build
+++ b/meson.build
@@ -2,7 +2,7 @@
 # General
 # ============================================================================
 project('libgtkmusic', ['vala', 'c'],
-         version: '0.4',
+         version: '0.5',
          meson_version: '>= 0.44.0')
 
 author_name = 'Leandro Resende Mattioli'
@@ -32,7 +32,7 @@ conf_data = configuration_data()
 conf_data.set('author_name', author_name)
 conf_data.set('author_email', author_email)
 conf_data.set('author_contact', author_name + '<' + author_email + '>')
-conf_data.set('project_url', 'https://wiki.gnome.org/Projects/libgtkmusic')
+conf_data.set('project_url', 'https://gitlab.gnome.org/GNOME/libgtkmusic')
 conf_data.set('version_major', version_major)
 conf_data.set('version_minor', version_minor)
 conf_data.set('version', version)         # Build Version
@@ -97,8 +97,7 @@ if get_option('typelib')
         enable_typelib = true
         custom_target('gtkmusic typelib', 
             command: [
-                g_ir_compiler, '--shared-library', 
-                join_paths(get_option('libdir'), 'libgtkmusic.so'), # small hack
+                g_ir_compiler, '--shared-library', 'libgtkmusic.so', # small hack
                 '--output', '@OUTPUT@', join_paths(build_dir, gir_file)],
             output: typelib_file,
             depends: libgtkmusic,
diff --git a/python/example.py b/python/example.py
new file mode 100644
index 0000000..caed069
--- /dev/null
+++ b/python/example.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+gi.require_version('GtkMusic', '0.5')
+
+from gi.repository import Gtk, Gdk, GtkMusic
+
+def note_pressed(widget, event, midi_code):
+        print('You pressed the note with MIDI code %d!' % midi_code)
+
+win = Gtk.Window()
+piano = GtkMusic.Piano.new()  # correct way to instantiate the widget
+
+piano.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
+piano.connect('note_pressed',  note_pressed)
+win.connect('destroy', Gtk.main_quit)
+
+win.add(piano)
+
+win.show_all()
+Gtk.main()
\ No newline at end of file
diff --git a/python/virtualpiano.py b/python/virtualpiano.py
new file mode 100644
index 0000000..7ffbb39
--- /dev/null
+++ b/python/virtualpiano.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+gi.require_version('GtkMusic', '0.5')
+
+import fluidsynth
+from gi.repository import Gtk, Gdk, GtkMusic
+
+HIGHLIGHT_COLOR = [0.5, 0.5, 0.5, 1.0]
+
+def note_pressed(widget, event, midi_code):
+    print('Note %d pressed' % midi_code)
+    fs.noteon(0, midi_code, 30)
+    widget.mark_midi(midi_code, HIGHLIGHT_COLOR)
+    widget.redraw()
+
+def note_released(widget, event, midi_code):
+    print('Note %d released' % midi_code)
+    fs.noteoff(0, midi_code)
+    widget.unmark_midi(midi_code)
+    widget.redraw()
+
+
+win = Gtk.Window()
+piano = GtkMusic.Piano.new()  # correct way to instantiate the widget
+piano.set_size_request(480, 160)
+
+fs = fluidsynth.Synth()
+fs.start(driver='alsa', device='hw:0')  # change to meet to your settings
+sfid = fs.sfload('/usr/share/sounds/sf2/FluidR3_GM.sf2')  # your soundfont here
+fs.program_select(0, sfid, 0, 0)
+
+piano.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | 
+                 Gdk.EventMask.BUTTON_RELEASE_MASK)
+piano.connect('note_pressed',  note_pressed)
+piano.connect('note_released', note_released)
+win.connect('destroy', Gtk.main_quit)
+
+win.add(piano)
+
+win.show_all()
+try:
+    Gtk.main()
+finally:
+    fs.delete()
\ No newline at end of file
diff --git a/src/GuitarWidget.vala b/src/GuitarWidget.vala
index 5ed1931..e97cefe 100644
--- a/src/GuitarWidget.vala
+++ b/src/GuitarWidget.vala
@@ -23,7 +23,7 @@ public class GuitarString {
     /**
      * A random generator seed (vibration animation phase difference) 
      */
-    public double vibrateSeed;  //should be private with getter ?
+    public double vibrate_seed;  //should be private with getter ?
     
     /**
      * Guitar string color as a RGBA array of floats 
@@ -33,11 +33,11 @@ public class GuitarString {
     /**
      * Label color as a RGBA array of floats 
      */
-    public float[] labelColor = {0.0f, 0.0f, 0.0f, 1.0f};
+    public float[] label_color = {0.0f, 0.0f, 0.0f, 1.0f};
     
     public GuitarString(string note) {
         this.note = note;
-        vibrateSeed = Random.next_double();
+        vibrate_seed = Random.next_double();
     }
 }
 
@@ -83,24 +83,24 @@ public class GuitarPosition {
     /** 
      * The guitar string index [0,5] associated to this guitar position 
      */
-    public ushort stringIndex;
+    public ushort string_index;
     
     /** 
      * The fret index associated to this guitar position 
      */
-    public ushort fretIndex;
+    public ushort fret_index;
     
-    public GuitarPosition(ushort stringIndex, ushort fretIndex) {
-        this.stringIndex = stringIndex;
-        this.fretIndex = fretIndex;
+    public GuitarPosition(ushort string_index, ushort fret_index) {
+        this.string_index = string_index;
+        this.fret_index = fret_index;
     }
       
     public static uint hash_func(GuitarPosition key) {
-        return (13 + key.stringIndex) * 23 + key.fretIndex;
+        return (13 + key.string_index) * 23 + key.fret_index;
     }
     
     public static bool equal_func(GuitarPosition a, GuitarPosition b) {
-        if(a.stringIndex == b.stringIndex && a.fretIndex == b.fretIndex)
+        if(a.string_index == b.string_index && a.fret_index == b.fret_index)
             return true;
         return false; 
     } 
@@ -140,56 +140,56 @@ public class Guitar : DrawingArea {
     /**
      * Render string labels (e.g.: EADGBE) 
      */
-    public bool showLabels = true;
+    public bool show_labels = true;
     
     /**
      * Show octaves in labels (e.g.: E4) 
      */
-    public bool detailedLabels = false;
+    public bool detailed_labels = false;
     
     /** 
      * Draw additional line in 1st fret 
      */
-    public bool highlightFirstFret = true;
+    public bool highlight_first_fret = true;
     
     /** 
      * Auto-redraw when a note is added (disable for manual management) 
      */
-    public bool autoUpdate = true; 
+    public bool auto_update = true; 
     
     /** 
      * Whether the guitar should be animated (string vibrations)
      */
-    private bool shouldAnimate = false;
+    private bool should_animate = false;
     
     //Grid properties
 
     /** 
      * Number of frets 
      */
-    public ushort fretNumber = 17;
+    public ushort fret_number = 17;
 
-    //public float[] gridBgColor = {0.57f, 0.39f, 0.30f, 1.0f};
+    //public float[] grid_bg_color = {0.57f, 0.39f, 0.30f, 1.0f};
 
     /**
      * Grid background color as a RGBA array of floats
      */
-    public float[] gridBgColor = {0.486f, 0.309f, 0.251f, 1.0f};
+    public float[] grid_bg_color = {0.486f, 0.309f, 0.251f, 1.0f};
 
     /** 
      * Fret color as a RGBA array of floats 
      */
-    public float[] fretColor = {0.6f, 0.6f, 0.6f, 1.0f};
+    public float[] fret_color = {0.6f, 0.6f, 0.6f, 1.0f};
 
     /** 
      * Collection of strings 
      */
-    public ArrayList<GuitarString> guitarStrings;
+    public ArrayList<GuitarString> guitar_strings;
 
     /**
      * Collection of fret marks 
      */
-    public HashSet<GuitarFretMark> fretMarks;
+    public HashSet<GuitarFretMark> fret_marks;
     
     //Advanced style properties
     //TODO :: Guitar styles (classical, electrical, guitar hero, music school)
@@ -211,7 +211,7 @@ public class Guitar : DrawingArea {
     /** 
      * Marked notes dictionary (position and mark style) 
      */
-    public HashMap<GuitarPosition, MarkedNoteStyle> markedNotes;
+    public HashMap<GuitarPosition, MarkedNoteStyle> marked_notes;
     
     //=========================================================================
     //Private properties
@@ -241,20 +241,18 @@ public class Guitar : DrawingArea {
     * Create a new Guitar widget, which minimum size is defined to 170x60
     **/
     public Guitar () {
-        //stdout.printf("Creating guitar [START]..."); stdout.flush();
-        add_events (Gdk.EventMask.BUTTON_PRESS_MASK
-                  | Gdk.EventMask.BUTTON_RELEASE_MASK);
-        set_size_request (170, 60);  //minimum widget size
-        guitarStrings = new ArrayList<GuitarString> ();
-        fretMarks = new HashSet<GuitarFretMark> ();
-        markedNotes = new HashMap<GuitarPosition, MarkedNoteStyle> 
+        /* add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+                  | Gdk.EventMask.BUTTON_RELEASE_MASK); */
+        guitar_strings = new ArrayList<GuitarString> ();
+        fret_marks = new HashSet<GuitarFretMark> ();
+        marked_notes = new HashMap<GuitarPosition, MarkedNoteStyle> 
                           ( (Gee.HashDataFunc?) GuitarPosition.hash_func,
                             (Gee.EqualDataFunc?) GuitarPosition.equal_func );
         foreach(string s in defaultStrings)
-            guitarStrings.add(new GuitarString(s));
+            guitar_strings.add(new GuitarString(s));
         foreach(ushort i in defaultFretMarks)
-            fretMarks.add(new GuitarFretMark(i));
-        //stdout.printf("Creating guitar [END]..."); stdout.flush();    
+            fret_marks.add(new GuitarFretMark(i));
+        set_size_request (170, 60);  //minimum widget size
     }
     
     //=========================================================================
@@ -265,7 +263,7 @@ public class Guitar : DrawingArea {
      * Start the animation on strings set to vibrate
      */ 
     public void start_animation() {
-        shouldAnimate = true;
+        should_animate = true;
         Timeout.add (10, update_animation);
     }
     
@@ -273,7 +271,7 @@ public class Guitar : DrawingArea {
      * Stop the string vibration animation
      */
     public void stop_animation() {
-        shouldAnimate = false;
+        should_animate = false;
         animateInstant = 0;
     }
     
@@ -283,34 +281,34 @@ public class Guitar : DrawingArea {
     private bool update_animation() {
         animateInstant += 0.3f;
         redraw();
-        return shouldAnimate;
+        return should_animate;
     }
     
     //====Marking-related======================================================
     
    /**
     * Highlight a position (string and fret) in the instrument
-    * @param stringIndex The string number (top string equals to 0)
-    * @param fretIndex The fret number
+    * @param string_index The string number (top string equals to 0)
+    * @param fret_index The fret number
     **/
-    public void mark_position(ushort stringIndex, ushort fretIndex,
+    public void mark_position(ushort string_index, ushort fret_index,
                               float[] color = {0.0f, 0.0f, 0.0f, 1.0f}) {
-        var key = new GuitarPosition(stringIndex, fretIndex);
-        markedNotes[key] = new MarkedNoteStyle(color);
-        if(autoUpdate)
+        var key = new GuitarPosition(string_index, fret_index);
+        marked_notes[key] = new MarkedNoteStyle(color);
+        if(auto_update)
             redraw();
     }
 
    /**
     * Remove the mark of a position (string and fret) in the instrument
-    * @param stringIndex The string number (topmost string equals to 0)
-    * @param fretIndex The fret number
+    * @param string_index The string number (topmost string equals to 0)
+    * @param fret_index The fret number
     **/    
-    public void unmark_position(ushort stringIndex, ushort fretIndex) {
-        var key = new GuitarPosition(stringIndex, fretIndex);
-        if(markedNotes.has_key(key))
-            markedNotes.unset(key);
-        if(autoUpdate)
+    public void unmark_position(ushort string_index, ushort fret_index) {
+        var key = new GuitarPosition(string_index, fret_index);
+        if(marked_notes.has_key(key))
+            marked_notes.unset(key);
+        if(auto_update)
             redraw();
     }
     
@@ -318,8 +316,8 @@ public class Guitar : DrawingArea {
     * Remove all marked notes in the Guitar view
     **/ 
     public void unmark_all() {
-        markedNotes.clear();
-        if(autoUpdate)
+        marked_notes.clear();
+        if(auto_update)
             redraw();
     }
     
@@ -329,15 +327,15 @@ public class Guitar : DrawingArea {
     **/
     public void mark_note(string note, 
                           float[] color = {0.0f, 0.0f, 0.0f, 1.0f}) {
-        bool oldAutoUpdate = autoUpdate;
+        bool oldAutoUpdate = auto_update;
         var positions = find_positions(note);
         if(positions == null)
             return;
         foreach(GuitarPosition k in positions) {
-            mark_position(k.stringIndex, k.fretIndex, color);
+            mark_position(k.string_index, k.fret_index, color);
         }
-        autoUpdate = oldAutoUpdate;
-        if(autoUpdate)
+        auto_update = oldAutoUpdate;
+        if(auto_update)
             redraw();
     }
     
@@ -346,15 +344,15 @@ public class Guitar : DrawingArea {
     * @param note A musical note in scientific notation (examples: F#4 , C)
     **/    
     public void unmark_note(string note) {
-        bool oldAutoUpdate = autoUpdate;
+        bool oldAutoUpdate = auto_update;
         var positions = find_positions(note);
         if(positions == null)
             return;
         foreach(GuitarPosition k in positions) {
-            unmark_position(k.stringIndex, k.fretIndex);
+            unmark_position(k.string_index, k.fret_index);
         }
-        autoUpdate = oldAutoUpdate;
-        if(autoUpdate)
+        auto_update = oldAutoUpdate;
+        if(auto_update)
             redraw();
     }
     
@@ -362,16 +360,16 @@ public class Guitar : DrawingArea {
     
     /**
      * Compute the fret index to accomplish a given note in a given string
-     * @param stringIndex The guitar string index
+     * @param string_index The guitar string index
      * @param note The musical note in scientific notation
      * @return The position where the note can be found or -1
      **/
-    public short note_position_in_string(ushort stringIndex, string note) {
-        string firstNote = guitarStrings[stringIndex].note;
+    public short note_position_in_string(ushort string_index, string note) {
+        string firstNote = guitar_strings[string_index].note;
         var midiA = MusicalNotes.get_note_as_midi_code(firstNote);
         var midiB = MusicalNotes.get_note_as_midi_code(note);
         short result = (short) (midiB - midiA);
-        if(result > fretNumber)
+        if(result > fret_number)
             return -1;
         return result;
     }
@@ -384,7 +382,7 @@ public class Guitar : DrawingArea {
         if(!MusicalNotes.validate(note) && !MusicalNotes.is_incomplete(note))
             return null;
 
-        short fretIndex;
+        short fret_index;
         HashSet<string> notesWithOctaves;
         var validPositions = new HashSet<GuitarPosition> (
             (Gee.HashDataFunc?) GuitarPosition.hash_func,
@@ -401,10 +399,10 @@ public class Guitar : DrawingArea {
         
         //Finding positions
         foreach(string n in notesWithOctaves) {
-            for(var s = 0 ; s < guitarStrings.size ; s++) {
-                fretIndex = note_position_in_string(s, n);
-                if(fretIndex >= 0)
-                    validPositions.add(new GuitarPosition(s, fretIndex));
+            for(var s = 0 ; s < guitar_strings.size ; s++) {
+                fret_index = note_position_in_string(s, n);
+                if(fret_index >= 0)
+                    validPositions.add(new GuitarPosition(s, fret_index));
             }
         }
         return validPositions;
@@ -414,9 +412,9 @@ public class Guitar : DrawingArea {
     * Get a MIDI code from a guitar position
     **/
     public ushort position_to_midi(GuitarPosition position) {
-        string first_note = guitarStrings[position.stringIndex].note;
+        string first_note = guitar_strings[position.string_index].note;
         ushort midi = MusicalNotes.get_note_as_midi_code(first_note);
-        midi += position.fretIndex;
+        midi += position.fret_index;
         return midi;
     }
     
@@ -450,12 +448,12 @@ public class Guitar : DrawingArea {
            (stringOffset < (1 - y_tolerance) && stringOffset > y_tolerance) )
            return null;
         
-        ushort fretIndex = (ushort) (x/fretSpacing);
-        ushort stringIndex = (ushort) (y/stringSpacing);
+        ushort fret_index = (ushort) (x/fretSpacing);
+        ushort string_index = (ushort) (y/stringSpacing);
         if(stringOffset > (1 - y_tolerance)) //in order to get nearest string
-            stringIndex += 1;
+            string_index += 1;
         
-        return new GuitarPosition(stringIndex, fretIndex);
+        return new GuitarPosition(string_index, fret_index);
     }
     
     //=====Events==============================================================
@@ -517,7 +515,7 @@ public class Guitar : DrawingArea {
         height = get_allocated_height (); //total height for the widget
 
         gridHeight = 0.8 * height;
-        if(showLabels) {
+        if(show_labels) {
             gridWidth = 0.95 * width;
             cr.select_font_face("monospace", Cairo.FontSlant.NORMAL, 
                                 Cairo.FontWeight.NORMAL);
@@ -529,8 +527,8 @@ public class Guitar : DrawingArea {
             
         gridX = width - gridWidth; //grid start point (X)
         gridY = (height - gridHeight) / 2; //grid start point (Y)
-        stringSpacing = gridHeight / (guitarStrings.size - 1); //segfault with glade
-        fretSpacing = gridWidth / fretNumber;  
+        stringSpacing = gridHeight / (guitar_strings.size - 1); //segfault with glade
+        fretSpacing = gridWidth / fret_number;  
         fretMarkRadius = 0.5 * Math.fmin(fretSpacing / 2, stringSpacing / 2);
         markedNoteRadius = 0.7 * Math.fmin(fretSpacing / 2, stringSpacing / 2);
         //stdout.printf("Calculate dimensions [END]."); stdout.flush();
@@ -542,8 +540,8 @@ public class Guitar : DrawingArea {
     **/    
     private void draw_base(Cairo.Context cr) {
         cr.save();
-        cr.set_source_rgba(gridBgColor[0], gridBgColor[1], 
-                           gridBgColor[2], gridBgColor[3]);
+        cr.set_source_rgba(grid_bg_color[0], grid_bg_color[1], 
+                           grid_bg_color[2], grid_bg_color[3]);
         cr.rectangle(gridX + fretSpacing, gridY, gridWidth, gridHeight);
         cr.fill();
         cr.restore();
@@ -559,16 +557,16 @@ public class Guitar : DrawingArea {
         string stringLabel;
         cr.set_line_width(2);
         cr.save();
-        for(var i = 0; i < guitarStrings.size ; i++) {
-            str = guitarStrings[i];
+        for(var i = 0; i < guitar_strings.size ; i++) {
+            str = guitar_strings[i];
             cr.set_source_rgba(str.color[0], str.color[1], 
                                str.color[2], str.color[3]);
             var stringY = gridY + i * stringSpacing;
             cr.move_to (gridX, stringY);
-            if(!str.vibrate || !shouldAnimate)
+            if(!str.vibrate || !should_animate)
                 cr.line_to (gridX + width, stringY);
             else {
-                var instant = Math.sin(animateInstant + 4 * str.vibrateSeed);
+                var instant = Math.sin(animateInstant + 4 * str.vibrate_seed);
                 var amplitude = instant * 0.1 * stringSpacing;
                 cr.curve_to (gridX, stringY + amplitude, 
                              gridX + width, stringY + amplitude,
@@ -577,9 +575,9 @@ public class Guitar : DrawingArea {
             cr.stroke();
             cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
             Cairo.TextExtents te;
-            if (showLabels) {
-                stringLabel = guitarStrings[i].note;
-                if (!detailedLabels)
+            if (show_labels) {
+                stringLabel = guitar_strings[i].note;
+                if (!detailed_labels)
                     stringLabel = stringLabel[0:stringLabel.length - 1];
                 cr.text_extents(stringLabel, out te);
                 cr.move_to(gridX - 0.5 - te.x_bearing - te.width, 
@@ -597,16 +595,16 @@ public class Guitar : DrawingArea {
     */  
     private void draw_frets(Cairo.Context cr) {
         cr.save();
-        cr.set_source_rgba(fretColor[0], fretColor[1], 
-                           fretColor[2], fretColor[3]);
-        for(var j = 1; j < fretNumber; j++) {
+        cr.set_source_rgba(fret_color[0], fret_color[1], 
+                           fret_color[2], fret_color[3]);
+        for(var j = 1; j < fret_number; j++) {
             var fretX = gridX + j * fretSpacing;
             cr.move_to (fretX, gridY);
             cr.line_to (fretX, gridY + gridHeight);
         }
         cr.stroke();
         cr.restore();
-        if(!highlightFirstFret)
+        if(!highlight_first_fret)
             return;
         cr.save ();
         cr.set_line_width (0.1 * fretSpacing);
@@ -621,10 +619,10 @@ public class Guitar : DrawingArea {
     * @param cr The drawing context for the widget
     */  
     private void draw_fret_marks(Cairo.Context cr) {
-        if(fretMarks.size == 0)
+        if(fret_marks.size == 0)
             return;
         cr.save ();
-        foreach (GuitarFretMark fm in fretMarks) {
+        foreach (GuitarFretMark fm in fret_marks) {
             var p = fm.position;
             cr.set_source_rgba(fm.color[0], fm.color[1], 
                                fm.color[2], fm.color[3]);
@@ -641,15 +639,15 @@ public class Guitar : DrawingArea {
     * @param cr The drawing context for the widget
     */  
     private void draw_marked_notes(Cairo.Context cr) {
-        if(markedNotes.size == 0)
+        if(marked_notes.size == 0)
             return;
         cr.save ();
-        foreach (var entry in markedNotes.entries) {
+        foreach (var entry in marked_notes.entries) {
             var k = entry.key;
             var v = entry.value;
             cr.set_source_rgba(v.color[0], v.color[1], v.color[2], v.color[3]);
-            var x = gridX + (k.fretIndex + 0.5) * fretSpacing;
-            var y = gridY + k.stringIndex * stringSpacing;
+            var x = gridX + (k.fret_index + 0.5) * fretSpacing;
+            var y = gridY + k.string_index * stringSpacing;
             cr.move_to(x, y);
             cr.arc (x, y, markedNoteRadius, 0, 2 * Math.PI);
             cr.fill();
@@ -672,7 +670,6 @@ public class Guitar : DrawingArea {
         }
         Cairo.Region region = window.get_clip_region ();
         window.invalidate_region (region, true);
-        window.process_updates (true);
     }
 }
 
diff --git a/src/MusicalNotes.vala b/src/MusicalNotes.vala
index 483ca01..a810b16 100644
--- a/src/MusicalNotes.vala
+++ b/src/MusicalNotes.vala
@@ -19,8 +19,8 @@ public class MusicalNotes {
     /**
      * Musical notes, without octaves
      **/
-    public const string[] note_names = { "C", "C#", "D", "D#", "E", "F", 
-                                      "F#", "G", "G#", "A", "A#", "B" };
+    public const string[] NOTE_NAMES = { "C", "C#", "D", "D#", "E", "F", 
+                                         "F#", "G", "G#", "A", "A#", "B" };
     
     /**
      * All standard diatonic intervals, in order.
@@ -63,8 +63,8 @@ public class MusicalNotes {
     * @return True if it's a note without octave or false otherwise
     **/
     public static bool is_incomplete(string needle) {
-        for(var i = 0 ; i < note_names.length ; i++)
-            if(note_names[i] == needle)
+        for(var i = 0 ; i < NOTE_NAMES.length ; i++)
+            if(NOTE_NAMES[i] == needle)
                 return true;
         return false;
     }
@@ -135,8 +135,8 @@ public class MusicalNotes {
             throw new MusicalNoteError.INVALID_NOTE("Invalid octave!");
         high = (short) octave.digit_value();            //Saving "MSB"
         note_name = note[0 : note.length - 1];
-        for(var i = 0 ; i < note_names.length ; i++) {
-            if(note_names[i] == note_name) {
+        for(var i = 0 ; i < NOTE_NAMES.length ; i++) {
+            if(NOTE_NAMES[i] == note_name) {
                 low = i;                     //Getting "LSB"
                 break;
             }
@@ -160,7 +160,7 @@ public class MusicalNotes {
     *  1. Subtract 18 from the MIDI code
     *  2. Get the integer part of the division by 12 as the octave
     *  3. Get the modulus division as the note index
-    *  4. Construct note indexing the note_names list and adding the octave
+    *  4. Construct note indexing the NOTE_NAMES list and adding the octave
     *
     * @param midi The note valid MIDI code
     * @return The note as a string or ""
@@ -174,7 +174,7 @@ public class MusicalNotes {
         midi -= 12;
         ushort octave = (ushort) (midi / 12);
         ushort note_index = (ushort) (midi % 12);
-        string note = note_names[note_index];
+        string note = NOTE_NAMES[note_index];
         note += octave.to_string();
         return note;
     }
diff --git a/src/PianoWidget.vala b/src/PianoWidget.vala
index 7626a18..4ba6352 100644
--- a/src/PianoWidget.vala
+++ b/src/PianoWidget.vala
@@ -2,7 +2,6 @@ using Gtk;
 using Gee;
 
 //TODO Make a QCAD picture with all relevant dimensions and offsets
-//TODO Library Makefile and installation instructions
 //TODO Labels
 
 /* 
@@ -11,9 +10,9 @@ using Gee;
     => low, the implementation of MusicalNotes.midi_is_accident is "cheap"
  - what's the cost of getting the x coordinates for a MIDI code ?
     => low, little math in a loop with a maximum of 12-iterations
- - iterate markedNotes hash map VS check for keys while iterating in the other
+ - iterate marked_notes hash map VS check for keys while iterating in the other
    draw routines
-    => iterate markedNotes, if done only once, seems less expensive
+    => iterate marked_notes, if done only once, seems less expensive
  - what's the cost of replacing rectangles by polygons for natural keys ?
     => the polygon form depends whether the key is preceeded or followed by
        an accident.
@@ -69,25 +68,68 @@ public class Piano : DrawingArea {
     //Properties
     //=========================================================================
     
+    /**
+     * Possible keys labels positions
+     */
     public enum LabelPosition {
         UP,
         DOWN
     }
-    public bool autoUpdate = true;
-    public ushort key_count = 24;   //Number of keys
-    public ushort firstNote = 36;  //C2
+
+    /**
+     * Automatically redraw the piano whenever there's a change
+     */
+    public bool auto_update = true;
+
+    /**
+     * Number of keys
+     */
+    public ushort key_count = 24;
+
+    /**
+     * MIDI Code of the first key's note (Defaults to C2)
+     */
+    public ushort first_note = 36;  //C2
+
+    /**
+     * RGBA color used to draw natural keys
+     */
     public float[] nat_key_color = {1.0f, 1.0f, 1.0f, 1.0f};
+
+    /**
+     * RGBA color used to draw accident keys
+     */
     public float[] accident_key_color = {0.0f, 0.0f, 0.0f, 1.0f};
-    public bool showLabels = false;      //Show note labels
-    public bool detailedLabels = false; //Show octaves in labels (e.g. E4)
-    public LabelPosition labelsPosition = LabelPosition.UP;
+
+    /**
+     * Whether note names should be drawn
+     */
+    public bool show_labels = false;
+    
+    /**
+     * Show octaves should be added in labels (e.g. E4)
+     */
+    public bool detailed_labels = false;
+
+    /**
+     * Labels position
+     */
+    public LabelPosition labels_position = LabelPosition.UP;
+
+    /**
+     * A style for a given marked note (currently only a color)
+     */
     public class MarkedNoteStyle {
-        public float[] color = {0.0f, 0.0f, 0.0f, 1.0f};
+        public float[] color = {0.5f, 0.5f, 0.5f, 1.0f};
         public MarkedNoteStyle(float[] color) {
             this.color = color;
         }
     }
-    public HashMap<ushort, MarkedNoteStyle> markedNotes;
+
+    /**
+     * Dictionary of marked notes
+     */
+    public HashMap<ushort, MarkedNoteStyle> marked_notes;
     
     //=========================================================================
     //Private properties
@@ -97,7 +139,6 @@ public class Piano : DrawingArea {
     private ushort v_padding = 2;
     private float accident_key_height = 0.7f;
     private float accident_key_width = 0.4f;
-    private float x_min_natk_dist = 0.1f;
     private ushort nat_keys;
     private double piano_width;
     private double piano_height;
@@ -112,27 +153,27 @@ public class Piano : DrawingArea {
     //Methods
     //=========================================================================
    
-   /**
-    * Create a new Piano widget, which minimum size is defined to 120x40
-    **/
+    /**
+     * Create a new Piano widget, which minimum size is defined to 120x40
+     **/
     public Piano() {
-        add_events (Gdk.EventMask.BUTTON_PRESS_MASK
-                  | Gdk.EventMask.BUTTON_RELEASE_MASK);
+        /* add_events (Gdk.EventMask.BUTTON_PRESS_MASK
+                  | Gdk.EventMask.BUTTON_RELEASE_MASK); */
+        marked_notes = new HashMap<ushort, MarkedNoteStyle> ();
         set_size_request (120, 40);  //minimum widget size
-        markedNotes = new HashMap<ushort, MarkedNoteStyle> ();
     }
     
     //====Marking-related======================================================
     
-   /**
-    * Highlight a key corresponding to a MIDI code
-    * @param midi_note A valid MIDI code (in range: 21 .. 108)
-    * @param color The color (in RGBA []) to fill the marked key (default: blue)
-    **/
+    /**
+     * Highlight a key corresponding to a MIDI code
+     * @param midi_note A valid MIDI code (in range: 21 .. 108)
+     * @param color The color (in RGBA []) to fill the marked key (default: blue)
+     **/
     public void mark_midi(ushort midi_note, 
                           float[] color = {0.0f, 0.0f, 0.5f, 1.0f}) {
-        markedNotes[midi_note] = new MarkedNoteStyle(color);
-        if(autoUpdate)
+        marked_notes[midi_note] = new MarkedNoteStyle(color);
+        if(auto_update)
             redraw();     
     }
     
@@ -141,9 +182,9 @@ public class Piano : DrawingArea {
     * @param midi_note A valid MIDI code (in range: 21 .. 108)
     **/
     public void unmark_midi(ushort midi_note) {
-        if(markedNotes.has_key(midi_note))
-            markedNotes.unset(midi_note);
-        if(autoUpdate)
+        if(marked_notes.has_key(midi_note))
+            marked_notes.unset(midi_note);
+        if(auto_update)
             redraw();    
     }
     
@@ -153,7 +194,7 @@ public class Piano : DrawingArea {
     **/
     public void mark_note(string note,
                           float[] color = {0.0f, 0.0f, 0.5f, 1.0f}) {
-        bool oldAutoUpdate = autoUpdate;
+        bool old_auto_update = auto_update;
 
         //Preparing list of keys to mark
         var positions = find_positions(note);
@@ -162,10 +203,10 @@ public class Piano : DrawingArea {
         
         //Adding keys to marked notes
         foreach(ushort u in positions)
-            markedNotes[u] = new MarkedNoteStyle(color);
+            marked_notes[u] = new MarkedNoteStyle(color);
         
-        autoUpdate = oldAutoUpdate;
-        if(autoUpdate)
+        auto_update = old_auto_update;
+        if(auto_update)
             redraw();
     }
 
@@ -174,7 +215,7 @@ public class Piano : DrawingArea {
     * @param note A musical note in scientific notation (examples: F#4 , C)
     **/
     public void unmark_note(string note) {
-        bool oldAutoUpdate = autoUpdate;
+        bool old_auto_update = auto_update;
         
         //Preparing list of keys to unmark
         var positions = find_positions(note);
@@ -183,10 +224,10 @@ public class Piano : DrawingArea {
         
         //Adding keys to marked notes
         foreach(ushort u in positions)
-            markedNotes.unset(u);
+            marked_notes.unset(u);
 
-        autoUpdate = oldAutoUpdate;
-        if(autoUpdate)
+        auto_update = old_auto_update;
+        if(auto_update)
             redraw();  
     }
     
@@ -194,8 +235,8 @@ public class Piano : DrawingArea {
     * Remove all marked notes in the Piano view
     **/ 
     public void unmark_all() {
-        markedNotes.clear();
-        if(autoUpdate)
+        marked_notes.clear();
+        if(auto_update)
             redraw();
     }
     
@@ -214,7 +255,7 @@ public class Piano : DrawingArea {
         ushort r1_key, r2_key, r3_key; //regions (top-left, middle, top-right)
         bool curr_accident; //current note is an accident
         bool next_accident; //note after a horizontal step is an accident
-        for(var i = firstNote ; i < firstNote + key_count ; i++) {
+        for(var i = first_note ; i < first_note + key_count ; i++) {
             delta_x = x - midi_to_x(i);
             
             if(delta_x < key_width) {                     // in close region
@@ -259,8 +300,8 @@ public class Piano : DrawingArea {
      * @param midi_code A valid MIDI code, present in the piano range
      **/
     public double midi_to_x(ushort midi_code) {
-        ushort norm_key = midi_code - firstNote;
-        if(norm_key < 0 || norm_key > (firstNote + key_count))
+        ushort norm_key = midi_code - first_note;
+        if(norm_key < 0 || norm_key > (first_note + key_count))
             return -1; //TODO Throw exception ??
         double x = piano_x;
         x += (int) (norm_key / 12) * 7 * key_width; //skipping octaves
@@ -303,7 +344,7 @@ public class Piano : DrawingArea {
         ushort nat_keys = complete_octaves * 7; //7 natural-notes per octave
         ushort tmp_note;
         for(var i = 0; i < incomplete_octave; i++) { //iterating rem. keys
-            tmp_note = (firstNote + i) % 12; //normalized offset
+            tmp_note = (first_note + i) % 12; //normalized offset
             if(!MusicalNotes.midi_is_accident(tmp_note))
                 nat_keys += 1;   
         }
@@ -365,7 +406,6 @@ public class Piano : DrawingArea {
         }
         Cairo.Region region = window.get_clip_region ();
         window.invalidate_region (region, true);
-        window.process_updates (true);
     }
     
    /**
@@ -375,7 +415,7 @@ public class Piano : DrawingArea {
     private void calculate_dimensions(Cairo.Context cr) {
         width = get_allocated_width (); //total width for the widget
         height = get_allocated_height (); //total height for the widget
-        if(showLabels) {
+        if(show_labels) {
             piano_height = (0.8 * height) - 2 * v_padding;
              cr.select_font_face("monospace", Cairo.FontSlant.NORMAL, 
                                 Cairo.FontWeight.NORMAL);
@@ -412,15 +452,17 @@ public class Piano : DrawingArea {
         cr.stroke();
         
         //Redrawing marked natural keys
-        foreach(var entry in markedNotes.entries) {
-            if(!MusicalNotes.midi_is_accident(entry.key)) {
-                x = midi_to_x(entry.key);
-                cr.rectangle(x, y, key_width, piano_height);
-                cr.set_source_rgba(entry.value.color[0], entry.value.color[1],
-                                   entry.value.color[2], entry.value.color[3]);
-                cr.fill_preserve();
-                cr.set_source_rgba(0.0f, 0.0f, 0.0f, 1.0f);
-                cr.stroke();
+        if(marked_notes != null) {
+            foreach(var entry in marked_notes.entries) {
+                if(!MusicalNotes.midi_is_accident(entry.key)) {
+                    x = midi_to_x(entry.key);
+                    cr.rectangle(x, y, key_width, piano_height);
+                    cr.set_source_rgba(entry.value.color[0], entry.value.color[1],
+                                    entry.value.color[2], entry.value.color[3]);
+                    cr.fill_preserve();
+                    cr.set_source_rgba(0.0f, 0.0f, 0.0f, 1.0f);
+                    cr.stroke();
+                }
             }
         }
         
@@ -442,7 +484,7 @@ public class Piano : DrawingArea {
         //Drawing all accidentals
         cr.set_source_rgba(accident_key_color[0], accident_key_color[1],
                            accident_key_color[2], accident_key_color[3]);
-        for(var i = firstNote; i < firstNote + key_count ; i++) {
+        for(var i = first_note; i < first_note + key_count ; i++) {
             if(MusicalNotes.midi_is_accident(i))
                 cr.rectangle(x - w/2, y, w, h);
             else    
@@ -454,15 +496,17 @@ public class Piano : DrawingArea {
         
         
         //Redrawing marked accidentals
-        foreach(var entry in markedNotes.entries) {
-            if(MusicalNotes.midi_is_accident(entry.key)) {
-                x = midi_to_x(entry.key);
-                cr.rectangle(x - w/2, y, w, h);
-                cr.set_source_rgba(entry.value.color[0], entry.value.color[1],
-                                   entry.value.color[2], entry.value.color[3]);
-                cr.fill_preserve();
-                cr.set_source_rgba(0.0f, 0.0f, 0.0f, 1.0f);
-                cr.stroke();
+        if(marked_notes != null) {
+            foreach(var entry in marked_notes.entries) {
+                if(MusicalNotes.midi_is_accident(entry.key)) {
+                    x = midi_to_x(entry.key);
+                    cr.rectangle(x - w/2, y, w, h);
+                    cr.set_source_rgba(entry.value.color[0], entry.value.color[1],
+                                    entry.value.color[2], entry.value.color[3]);
+                    cr.fill_preserve();
+                    cr.set_source_rgba(0.0f, 0.0f, 0.0f, 1.0f);
+                    cr.stroke();
+                }
             }
         }
         
diff --git a/test/TestsGuitar.vala b/test/TestsGuitar.vala
index 40b4014..2ba2c4c 100644
--- a/test/TestsGuitar.vala
+++ b/test/TestsGuitar.vala
@@ -6,9 +6,9 @@ void note_pressed_callback(Guitar guitar, Gdk.EventButton event,
     stdout.printf("You clicked a %s!\n", guitar.position_to_note(pos));
     stdout.flush();
     if(event.button == 1) //left-click
-        guitar.mark_position(pos.stringIndex, pos.fretIndex);
+        guitar.mark_position(pos.string_index, pos.fret_index);
     else
-        guitar.unmark_position(pos.stringIndex, pos.fretIndex);
+        guitar.unmark_position(pos.string_index, pos.fret_index);
 }
 
 int main(string[] args) {
@@ -16,8 +16,8 @@ int main(string[] args) {
     var window = new Window ();
     var guitar = new Guitar ();
     guitar.note_pressed.connect(note_pressed_callback);
-    guitar.guitarStrings[0].vibrate = true;
-    guitar.guitarStrings[5].vibrate = true;
+    guitar.guitar_strings[0].vibrate = true;
+    guitar.guitar_strings[5].vibrate = true;
     guitar.start_animation();
     guitar.mark_position(0, 0, {0.4f, 0.0f, 0.0f, 1.0f});
     guitar.mark_position(1, 1);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]