[libgtkmusic] API refactoring, some bug fixes and sample code.
- From: Leandro Resende Mattioli <lmattioli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgtkmusic] API refactoring, some bug fixes and sample code.
- Date: Mon, 10 Dec 2018 16:27:12 +0000 (UTC)
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]