Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2012-06-20 13:19:34 (GMT)
committer Walter Bender <walter.bender@gmail.com>2012-06-20 13:19:34 (GMT)
commit4cdcd5d34ab3dbe1d6bc774b295717d7006b28a1 (patch)
tree378d1a853aef54f7f64e57f3042eba9c02f9fce7
parent5389b26abc545ab487a0fb0dea0327cafeb04381 (diff)
display current note
-rw-r--r--tuning_toolbar.py103
1 files changed, 98 insertions, 5 deletions
diff --git a/tuning_toolbar.py b/tuning_toolbar.py
index a8eae9a..21f765d 100644
--- a/tuning_toolbar.py
+++ b/tuning_toolbar.py
@@ -22,6 +22,7 @@ from config import ICONS_DIR, CAPTURE_GAIN, MIC_BOOST, XO1, XO15, XO175, XO30
from sugar.graphics.toolbutton import ToolButton
from sugar.graphics.combobox import ComboBox
from sugar.graphics.toolcombobox import ToolComboBox
+from sugar.graphics import style
import logging
log = logging.getLogger('measure-activity')
log.setLevel(logging.DEBUG)
@@ -30,8 +31,16 @@ log.setLevel(logging.DEBUG)
OCTAVES = ['C͵͵', 'C͵', 'C', 'c', 'c′', 'c′′', 'c′′′', 'c′′′′', 'c′′′′′']
NOTES = ['A', 'A♯/B♭', 'B', 'C', 'C♯/D♭', 'D', 'D♯/E♭', 'E', 'F', 'F♯/G♭',
'G', 'G♯/A♭']
+SHARP = '♯'
+FLAT = '♭'
A0 = 27.5
+C8 = 4186.01
TWELTHROOT2 = 1.05946309435929
+COLOR_RED = style.Color('#FF6060')
+COLOR_YELLOW = style.Color('#FFFF00')
+COLOR_GREEN = style.Color('#00FF00')
+SPAN = '<span foreground="%s"><big><b>%s</b></big></span>'
+
class TuningToolbar(gtk.Toolbar):
''' The toolbar for tuning instruments '''
@@ -41,11 +50,12 @@ class TuningToolbar(gtk.Toolbar):
self.activity = activity
self._show_tuning_line = False
+ self._updating_note = True
# Set up Tuning Combo box
self._tuning_combo = ComboBox()
self.tuning = [_('None'), _('Guitar'), _('Violin'), _('Viola'),
- _('Cello'), _('Bass'), _('Charango')]
+ _('Cello'), _('Bass'), _('Charango'), _('Recorder')]
self._tuning_changed_id = self._tuning_combo.connect(
'changed', self.update_tuning_control)
for i, s in enumerate(self.tuning):
@@ -87,8 +97,11 @@ class TuningToolbar(gtk.Toolbar):
self._notes_tool = ToolComboBox(self._notes_combo)
self.insert(self._notes_tool, -1)
+ # The entry is used to display a note or for direct user input
self._freq_entry = gtk.Entry()
- self._freq_entry.set_text('440')
+ self._freq_entry.set_text('440') # A
+ self._freq_entry_changed_id = self._freq_entry.connect(
+ 'changed', self.update_freq_entry)
if hasattr(self._freq_entry, 'set_tooltip_text'):
self._freq_entry.set_tooltip_text(
_('Enter a frequency to display.'))
@@ -116,17 +129,89 @@ class TuningToolbar(gtk.Toolbar):
self._harmonic.set_tooltip(_('Show harmonics.'))
self._harmonic.connect('clicked', self.harmonic_cb)
+ if self.activity.has_toolbarbox:
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = True
+ self.insert(separator, -1)
+
+ self._play_tone = ToolButton('media-playback-start')
+ self._play_tone.show()
+ self.insert(self._play_tone, -1)
+ self._play_tone.set_tooltip(_('Play a note.'))
+ self._play_tone.connect('clicked', self.play_cb)
+
+ if self.activity.has_toolbarbox:
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ separator.set_expand(True)
+ self.insert(separator, -1)
+
+ self.label = gtk.Label('')
+ self.label.set_use_markup(True)
+ self.label.show()
+ toolitem = gtk.ToolItem()
+ toolitem.add(self.label)
+ self.insert(toolitem, -1)
+ toolitem.show()
+
self.show_all()
def update_note(self, *args):
''' Calculate the frequency based on octave and note combos '''
- f = A0 * pow(TWELTHROOT2, self._notes_combo.get_active() + \
+ if not hasattr(self, '_freq_entry'): # Still setting up toolbar
+ return
+ freq = A0 * pow(TWELTHROOT2, self._notes_combo.get_active() + \
(self._octave_combo.get_active() * 12))
- self._freq_entry.set_text(str(f))
+ self._updating_note = True
+ self._freq_entry.set_text('%0.3f' % (freq))
+ self.label.set_markup(SPAN % (style.COLOR_WHITE.get_html(),
+ NOTES[self._notes_combo.get_active()]))
if self._show_tuning_line:
- self.activity.wave.tuning_line = f
+ self.activity.wave.tuning_line = freq
return
+ def update_freq_entry(self, *args):
+ # Calcualte a note from a frequency
+ if not self._updating_note: # Only if user types in a freq.
+ try:
+ freq = float(self._freq_entry.get_text())
+ # Only consider notes in piano range
+ if freq < A0 * 0.97:
+ self.label.set_text('< A0')
+ return
+ if freq > C8 * 1.03:
+ self.label.set_text('> C8')
+ return
+ for i in range(88):
+ f = A0 * pow(TWELTHROOT2, i)
+ if freq > f * 0.97 and freq < f * 1.03:
+ label = NOTES[i % 12]
+ # calculate if we are sharp or flat
+ if freq < f * 0.98:
+ label = '%s %s %s' % (FLAT, label, FLAT)
+ self.label.set_markup(SPAN % (
+ COLOR_RED.get_html(), label))
+ elif freq < f * 0.99:
+ label = '%s %s %s' % (FLAT, label, FLAT)
+ self.label.set_markup(SPAN % (
+ COLOR_YELLOW.get_html(), label))
+ elif freq > f * 1.02:
+ label = '%s %s %s' % (SHARP, label, SHARP)
+ self.label.set_markup(SPAN % (
+ COLOR_RED.get_html(), label))
+ elif freq > f * 1.01:
+ label = '%s %s %s' % (SHARP, label, SHARP)
+ self.label.set_markup(SPAN % (
+ COLOR_YELLOW.get_html(), label))
+ else:
+ self.label.set_markup(SPAN % (
+ style.COLOR_WHITE.get_html(), label))
+ return
+ except ValueError:
+ return
+ self._updating_note = False
+
+
def update_tuning_control(self, *args):
''' Callback for tuning control '''
self.activity.wave.instrument = \
@@ -153,9 +238,17 @@ class TuningToolbar(gtk.Toolbar):
freq = self._freq_entry.get_text()
try:
self.activity.wave.tuning_line = float(freq)
+ if freq < 0:
+ freq = -freq
self._new_tuning_line.set_icon('tuning-tools-off')
self._new_tuning_line.set_tooltip(_('Hide tuning line.'))
self._show_tuning_line = True
except ValueError:
self.activity.wave.tuning_line = 0.0
self._freq_entry.set_text('0')
+
+ def play_cb(self, *args):
+ ''' Play a tone at current frequency '''
+ # TODO: conflict with gstreamer?
+ f = float(self._freq_entry.get_text())
+ os.system('speaker-test -t sine -l 1 -f %f' % (f))