chordvoicing.py :  » Business-Application » GNU-Solfege » solfege-3.16.3 » solfege » exercises » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Business Application » GNU Solfege 
GNU Solfege » solfege 3.16.3 » solfege » exercises » chordvoicing.py
# GNU Solfege - free ear training software
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008  Tom Cato Amundsen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import absolute_import

import gtk

from solfege import abstract
from solfege import gu
from solfege import lessonfile
from solfege import mpd
from solfege import soundcard

class Teacher(abstract.Teacher):
    OK = 0
    ERR_PICKY = 1
    #UGH should we do this here
    def __init__(self, exname):
        abstract.Teacher.__init__(self, exname)
        self.lessonfileclass = lessonfile.QuestionsLessonfile
    def new_question(self):
        """
        return 1 if the teacher has a question to ask
        UI will never call this function unless we have a usable lessonfile.
        """
        assert self.m_P
        if self.get_bool('config/picky_on_new_question') \
                 and not(self.q_status in (self.QSTATUS_VOICING_SOLVED, self.QSTATUS_NO)):
            return Teacher.ERR_PICKY

        if self.m_P:
            self.m_P.select_random_question()
            self.q_status = self.QSTATUS_NEW
            return Teacher.OK
    def guess_chordtype(self, t):
        """
        return 1 if correct, None if not.
        This function will set self.q_status, and will raise an
        exception if the function is called with invalid value of
        q_status.

        Before we start: self.QSTATUS_NO
        After 'New' is clicked: self.QSTATUS_NEW

        if chordtype correct: self.QSTATUS_TYPE_SOLVED
        if chordtype wrong: self.QSTATUS_TYPE_WRONG

        if voicing correct self.QSTATUS_VOICING_SOLVED
        if voicing wrong: self.QSTATUS_VOICING_WRONG
        """
        if self.q_status in (self.QSTATUS_NEW, self.QSTATUS_TYPE_WRONG):
            if t == self.m_P.get_cname():
                self.q_status = self.QSTATUS_TYPE_SOLVED
                return 1
            else:
                self.q_status = self.QSTATUS_TYPE_WRONG
                return
    def guess_voicing(self, tones):
        """
        return 1 if correct, None if not.
        Gui should not call this function if the question is already solved.
        """
        v = self.m_P.get_music_as_notename_list('music')
        v.sort(mpd.compare_notenames)
        question_i = []
        for n in v:
            while n[-1] in ",'":
                n = n[:-1]
            question_i.append(mpd.notename_to_int(n))
        answer_i = []
        for n in tones:
            while n[-1] in ",'":
                n = n[:-1]
            answer_i.append(mpd.notename_to_int(n))
        if answer_i == question_i:
            self.q_status = self.QSTATUS_VOICING_SOLVED
            return 1
        self.q_status = self.QSTATUS_VOICING_WRONG
    def give_up(self):
        self.q_status = self.QSTATUS_VOICING_SOLVED

class Gui(abstract.LessonbasedGui):
    def __init__(self, teacher):
        abstract.LessonbasedGui.__init__(self, teacher)
        self.m_stacking_frame_min_height = 0

        ###############
        # practise_box
        ###############
        self.practise_box.set_spacing(gu.PAD)

        hbox = gu.bHBox(self.practise_box, True, True)
        hbox.set_spacing(gu.PAD)
        ##################
        # chordtype frame 
        ##################
        frame = gtk.Frame(_("Identify chord type"))
        hbox.pack_start(frame)
        self.g_chordtype_box = gtk.VBox()
        self.g_chordtype_box.set_border_width(gu.PAD_SMALL)
        frame.add(self.g_chordtype_box)

        #################
        # stacking frame
        #################
        self.g_stacking_frame = gtk.Frame(_("Chord voicing"))
        self.g_stacking_frame.set_sensitive(False)
        hbox.pack_start(self.g_stacking_frame)
        vbox = gtk.VBox()
        vbox.set_border_width(gu.PAD_SMALL)
        self.g_stacking_frame.add(vbox)
        t = gtk.Table(1, 1, 1)
        vbox.pack_start(t)
        self.g_source = gtk.VBox()
        t.attach(self.g_source, 0, 1, 0, 1, gtk.EXPAND|gtk.FILL)
        self.g_answer = gtk.VBox()
        t.attach(self.g_answer, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL)
        self.g_redo = gtk.Button("<<<")
        self.g_redo.connect('clicked', lambda o, self=self: self.fill_stacking_frame())
        vbox.pack_end(self.g_redo, False, False)

        self.g_flashbar = gu.FlashBar()
        self.practise_box.pack_start(self.g_flashbar, False)

        self.std_buttons_add(('new-chord', self.new_question),
            ('repeat', lambda _o: self.m_t.m_P.play_question()),
            ('repeat_arpeggio', lambda _o: self.m_t.m_P.play_question_arpeggio()),
            ('give_up', lambda _o, self=self: self.give_up()))
        self.practise_box.show_all()
        ##############
        # config_box #
        ##############
        self.config_box.set_spacing(gu.PAD_SMALL)
        self.add_random_transpose_gui()
    def new_question(self, widget=None):
        def exception_cleanup():
            soundcard.synth.stop()
            self.std_buttons_exception_cleanup()
            self.m_t.q_status = self.QSTATUS_NO
        # if we have no lessonfile, then we have no questions.
        if not self.m_t.m_P:
            return
        try:
            g = self.m_t.new_question()
            self.std_buttons_new_question()
            if g == Teacher.OK:
                self.std_buttons_new_question()
                self.clear_stacking_frame()
                self.g_stacking_frame.set_sensitive(False)
                for c in self.g_chordtype_box.get_children():
                    c.set_sensitive(True)
                self.m_t.m_P.play_question()
                self.g_flashbar.flash(_("Chord type"))
                self.g_chordtype_box.get_children()[0].grab_focus()
            elif g == Teacher.ERR_PICKY:
                self.g_flashbar.flash(_("You have to solve this question first."))
        except Exception, e:
            # This is one place where m_mpd_badcode might be set, since it will
            # be set if the exception is raisd by m_P.play_question(), but not
            # by select_random_question called by m_t.new_question()
            if isinstance(e, mpd.MpdException):
                if 'm_mpd_varname' not in dir(e):
                    e.m_mpd_varname = 'music'
                if 'm_mpd_badcode' not in dir(e):
                    e.m_mpd_badcode = self.m_t.m_P.get_question()['music'].get_err_context(e, self)
            if not self.standard_exception_handler(e, exception_cleanup):
                raise
    def clear_stacking_frame(self):
        for c in self.g_source.get_children() + self.g_answer.get_children():
            c.destroy()
    def fill_stacking_frame(self):
        """
        Create the buttons in stacking frame.
        """
        self.g_redo.set_sensitive(True)
        self.g_stacking_frame.set_sensitive(True)
        self.m_answer = []
        self.clear_stacking_frame()
        v = self.m_t.m_P.get_music_as_notename_list('music')
        v.sort()
        for n in v:
            nn = mpd.MusicalPitch.new_from_notename(n)
            b = gtk.Button(nn.get_user_notename())
            b.connect('clicked', self.on_notebutton_clicked, nn.get_notename(), nn.get_user_notename())
            self.g_source.pack_end(b, False, False)
            b.show()
        self.g_source.get_children()[0].grab_focus()
    def give_up(self, v=None):
        self.m_t.give_up()
        self.std_buttons_give_up()
        self.set_chordtype_frame_status_solved(self.m_t.m_P.get_cname())
        self.clear_stacking_frame()
        self.g_stacking_frame.set_sensitive(True)
        self.g_redo.set_sensitive(False)
        self.show_music()
    def on_chordtype_right_clicked(self, button, event, t):
        if event.button != 3:
            return
        if self.m_t.m_P and not self.m_t.m_P.header.enable_right_click:
            self.g_flashbar.flash(_("Right click is not allowed for this lesson file."))
            return
        if self.m_t.q_status == self.QSTATUS_NO:
            self.g_flashbar.flash(_("Click 'New chord' to begin."))
            return
        if self.m_t.q_status == self.QSTATUS_NEW:
            self.g_flashbar.flash(_("You should try to guess before right-clicking."))
            return
        if not self.m_t.m_P.has_question():
            return
        try:
            # We try first with the 'set' variable, as this is what is closest
            if 'set' in self.m_t.m_P.get_question():
                for idx, question in enumerate(self.m_t.m_P.m_questions):
                    if question.set == self.m_t.m_P.get_question().set \
                            and question.name.cval == t:
                        self.m_t.m_P.play_question(question)
                        return
            #
            for idx, question in enumerate(self.m_t.m_P.m_questions):
                if question.name.cval == button.get_data('chordtype'):
                    self.m_t.m_P.play_question(question)
                    return
        except Exception, e:
            if not self.standard_exception_handler(e):
                raise
    def on_chordtype_clicked(self, btn, t):
        if self.m_t.q_status == self.QSTATUS_NO:
            self.g_flashbar.flash(_("Click 'New chord' to begin."))
        elif self.m_t.q_status in (self.QSTATUS_NEW, self.QSTATUS_TYPE_WRONG):
            g = self.m_t.guess_chordtype(t)
            if g:
                self.g_flashbar.flash(_("Correct, now stack the tones"))
                self.set_chordtype_frame_status_solved(t)
                self.fill_stacking_frame()
            else:
                self.g_flashbar.flash(_("Wrong"))
        elif self.m_t.q_status in (self.QSTATUS_TYPE_SOLVED, self.QSTATUS_VOICING_WRONG):
            self.g_flashbar.flash(_("Type is already solved, now specify voicing."))
    def on_notebutton_clicked(self, btn, n, user_notename):
        newb = gtk.Button(user_notename)
        newb.show()
        btn.destroy()
        self.m_answer.append(n)
        self.g_answer.pack_end(newb, False, False)
        if not self.g_source.get_children():
            # no children mean that the user has finished answering
            if self.m_t.guess_voicing(self.m_answer):
                self.g_flashbar.flash(_("Correct"))
                self.show_music()
                self.std_buttons_answer_correct()
                self.g_redo.set_sensitive(False)
            else:
                self.g_flashbar.flash(_("Wrong"))
                self.std_buttons_answer_wrong()
                self.g_redo.grab_focus()
        else:
            self.g_source.get_children()[0].grab_focus()
    def show_music(self):
        self.clear_stacking_frame()
        md = mpd.musicdisplayer.MusicDisplayer()
        self.g_source.pack_start(md)
        md.show()
        md.display(r"\staff{ \clef %s < %s >}" % (
                mpd.select_clef(self.m_t.m_P.get_music_as_notename_string('music')),
                self.m_t.m_P.get_music_as_notename_string('music')), 20)
        # display the notenames on the buttons with octave info
        v = self.m_t.m_P.get_music_as_notename_list('music')
        v.sort(mpd.compare_notenames)
        for n in v:
            b = gtk.Button(mpd.MusicalPitch.new_from_notename(n).get_user_octave_notename())
            b.get_children()[0].set_use_markup(1)
            b.show()
            self.g_answer.pack_end(b, False, False)
    def fill_chordtype_box(self):
        for x in self.g_chordtype_box.get_children():
            x.destroy()
        if self.m_t.m_P:
            for name in [q.name for q in self.m_t.m_P.iterate_questions_with_unique_names()]:
                b = gtk.Button(name)
                b.set_data('chordtype', name.cval)
                self.g_chordtype_box.pack_start(b, False)
                b.connect('clicked', self.on_chordtype_clicked, name.cval)
                b.connect('button_release_event', self.on_chordtype_right_clicked, name)
                b.show()
    def set_chordtype_frame_status_solved(self, t):
        for c in self.g_chordtype_box.get_children():
            c.set_sensitive(c.get_data('chordtype')==t)
    def on_start_practise(self):
        self.set_lesson_heading(self.m_t.m_P.header.lesson_heading)
        self.g_random_transpose.set_text(str(self.m_t.m_P.header.random_transpose))
        self.std_buttons_start_practise()
        self.g_flashbar.require_size([
            _("You have to solve this question first."),
            _("Type is already solved, now specify voicing."),
        ])
        self.g_flashbar.delayed_flash(self.short_delay,
            _("Click 'New chord' to begin."))
        self.fill_chordtype_box()
        self.clear_stacking_frame()
        self.g_stacking_frame.set_sensitive(False)
    def on_end_practise(self):
        self.m_t.end_practise()
        self.std_buttons_end_practise()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.