def _mpd_exception(self, exception, sourcefile, lineno): m = gu.ExceptionDialog(exception) if 'm_mpd_varname' in dir(exception): m.add_text( _('Failed to parse the music in the variable "%(varname)s" in question number %(idx)i in the lesson file "%(lf)s".' ) % { 'idx': self.m_t.m_P._idx + 1, 'lf': lessonfile.uri_expand(self.m_t.m_P.m_filename), 'varname': exception.m_mpd_varname }) else: m.add_text( _('Failed to parse the music for question number %(idx)i in the lesson file "%(lf)s".' ) % { 'idx': self.m_t.m_P._idx + 1, 'lf': lessonfile.uri_expand(self.m_t.m_P.m_filename) }) if 'm_mpd_badcode' in dir(exception): m.add_nonwrapped_text(exception.m_mpd_badcode) m.add_text( _('The exception was caught in\n"%(filename)s", line %(lineno)i.') % { 'filename': sourcefile, 'lineno': lineno }) m.run() m.destroy()
def on_add_link_by_search(self, btn): dlg = SelectLessonfileBySearchDialog() while True: ret = dlg.run() if ret == gtk.RESPONSE_OK: self._add_filenames([os.path.abspath(lessonfile.uri_expand(dlg.m_filename))]) else: break dlg.destroy()
def on_edit_file(self, menuitem, linked): try: try: subprocess.call((cfg.get_string("programs/text-editor"), lessonfile.uri_expand(self.m_model[linked]))) except OSError, e: raise osutils.BinaryForProgramException("Text editor", cfg.get_string("programs/text-editor"), e) except osutils.BinaryForProgramException, e: solfege.win.display_error_message2(e.msg1, e.msg2)
def on_add_link_by_search(self, btn): dlg = SelectLessonfileBySearchDialog(editor_of(self)) while True: ret = dlg.run() if ret == Gtk.ResponseType.OK: self._add_filenames( [os.path.abspath(lessonfile.uri_expand(dlg.m_filename))]) else: break dlg.destroy()
def on_select_exercise(self, menuitem, filename): module = lessonfile.infocache.get(filename, 'module') if module not in self.ok_modules: print "only some modules work:", self.ok_modules return p = lessonfile.LessonfileCommon() p.parse_file(lessonfile.uri_expand(filename)) if module == 'idbyname': self._add_idbyname_lesson(p, filename) elif module == 'harmonicinterval': self._add_harmonicinterval_lesson(p, filename) elif module == 'melodicinterval': self._add_melodicinterval_lesson(p, filename) self.g_treeview.set_cursor((len(self.m_sections) - 1, ))
def on_select_exercise(self, menuitem, filename): module = lessonfile.infocache.get(filename, 'module') if module not in self.ok_modules: print "only some modules work:", self.ok_modules return p = lessonfile.LessonfileCommon() p.parse_file(lessonfile.uri_expand(filename)) if module == 'idbyname': self._add_idbyname_lesson(p, filename) elif module == 'harmonicinterval': self._add_harmonicinterval_lesson(p, filename) elif module == 'melodicinterval': self._add_melodicinterval_lesson(p, filename) self.g_treeview.set_cursor((len(self.m_sections)-1,))
def _mpd_exception(self, exception, sourcefile, lineno): m = gu.ExceptionDialog(exception) if 'm_mpd_varname' in dir(exception): m.add_text(_('Failed to parse the music in the variable "%(varname)s" in question number %(idx)i in the lesson file "%(lf)s".') % { 'idx': self.m_t.m_P._idx + 1, 'lf': lessonfile.uri_expand(self.m_t.m_P.m_filename), 'varname': exception.m_mpd_varname}) else: m.add_text(_('Failed to parse the music for question number %(idx)i in the lesson file "%(lf)s".') % {'idx': self.m_t.m_P._idx + 1, 'lf': lessonfile.uri_expand(self.m_t.m_P.m_filename)}) if 'm_mpd_badcode' in dir(exception): m.add_nonwrapped_text(exception.m_mpd_badcode) m.add_text(_('The exception was caught in\n"%(filename)s", line %(lineno)i.') % {'filename': sourcefile, 'lineno': lineno}) m.run() m.destroy()
def validate_stored_statistics(self, filename): """ Insert the filename and hash of the file into the lessonfiles table if it is not registered there already. If already there, compare the hash value of the file with what we have in the database. Remove all saved statistics and insert the new hash value if they do not match. Return doing nothing if the file does not exist. """ logging.debug("validate_stored_statistics(%s)", filename) if not os.path.isfile(lessonfile.uri_expand(filename)): logging.debug("validate_stored_statistics: file does not exist.") return cursor = self.conn.cursor() row = cursor.execute( "select hash, fileid from lessonfiles " "where filename=?", (filename, )).fetchone() cur_lessonfile_hash_value = hash_of_lessonfile(filename) if not row: # Ususally the filename exists in the database, but when running # the test suite, it does not, so we have the code here to add it. logging.debug("file %s not in database. Adding", filename) self.insert_file(filename) self.conn.commit() else: hashvalue, fileid = row if hashvalue != cur_lessonfile_hash_value: logging.debug(" hashvalue != cur_lessonfile_hash_value") replaces = solfege.lessonfile.infocache.get( filename, 'replaces') if not isinstance(replaces, list): replaces = [replaces] if not hashvalue in replaces: logging.debug(" hash value changed. Deleing statistics") solfege.db.delete_statistics(filename) cursor.execute( "update lessonfiles " "set hash=?, test_passed=?, test_result=0.0 where fileid=?", (cur_lessonfile_hash_value, None, fileid)) self.conn.commit() else: logging.debug(" hash value matched") else: logging.debug(" hashvalue matched")
def sheet_gen_questions(self, count, sdict): """ count -- how many questions should we generate. We use this value and not sdict['count'] because sometimes the app has some questions, and just need a few more. """ module = lessonfile.infocache.get(sdict['filename'], 'module') if module not in self.m_teachers: self.create_teacher(module) p = self.m_teachers[module].lessonfileclass() p.parse_file(lessonfile.uri_expand(sdict['filename'])) if module == 'idbyname': for x in self._sheet_gen_question_idbyname(p, count, sdict): yield x else: assert module in ('harmonicinterval', 'melodicinterval') for x in self._sheet_gen_question_interval(module, p, count, sdict): yield x
def load_file(self, filename): p = Dataparser({'yes': True, 'no': False}, {}) p.parse_file(filename) s = p.globals.setdefault('output_format', 'midi') s = s.lower() if s in self.g_output: self.g_output[s].set_active(True) else: # MIDI is the default format self.g_output['midi'].set_active(True) self.m_filename = filename if p.globals['fileformat_version'] == 1: lessonfile.require_mgr() self.g_named_tracks.set_active(p.globals.get('named_tracks', False)) for lesson in p.blocklists.setdefault('lesson', []): # In this loop we will set the filename column of the liststore # to None if there is any problem, and set a title mentioning # the unknown lesson_id or filename. if p.globals['fileformat_version'] == 1: try: filename = lessonfile.mgr.get(lesson['lesson_id'], 'filename') filename = lessonfile.mk_uri(filename) except lessonfile.mgr.UnknownLessonID, e: filename = None else: filename = lesson['filename'] if filename: if os.path.exists(lessonfile.uri_expand(filename)): fn = filename title = self.get_lessonfile_title(filename) else: fn = None title = _(u"«<b>%s</b>» was not found") % filename self.g_liststore.append((fn, title, lesson['count'], lesson['repeat'], lesson['delay'])) else: self.g_liststore.append((filename, _("Unknown lesson_id: <b>%s</b>") % lesson['lesson_id'], lesson['count'], lesson['repeat'], lesson['delay']))
def validate_stored_statistics(self, filename): """ Insert the filename and hash of the file into the lessonfiles table if it is not registered there already. If already there, compare the hash value of the file with what we have in the database. Remove all saved statistics and insert the new hash value if they do not match. Return doing nothing if the file does not exist. """ logging.debug("validate_stored_statistics(%s)", filename) if not os.path.isfile(lessonfile.uri_expand(filename)): logging.debug("validate_stored_statistics: file does not exist.") return cursor = self.conn.cursor() row = cursor.execute("select hash, fileid from lessonfiles " "where filename=?", (filename,)).fetchone() cur_lessonfile_hash_value = hash_of_lessonfile(filename) if not row: # Ususally the filename exists in the database, but when running # the test suite, it does not, so we have the code here to add it. logging.debug("file %s not in database. Adding", filename) self.insert_file(filename) self.conn.commit() else: hashvalue, fileid = row if hashvalue != cur_lessonfile_hash_value: logging.debug(" hashvalue != cur_lessonfile_hash_value") replaces = solfege.lessonfile.infocache.get(filename, 'replaces') if not isinstance(replaces, list): replaces = [replaces] if not hashvalue in replaces: logging.debug(" hash value changed. Deleing statistics") solfege.db.delete_statistics(filename) cursor.execute("update lessonfiles " "set hash=?, test_passed=?, test_result=0.0 where fileid=?", (cur_lessonfile_hash_value, None, fileid)) self.conn.commit() else: logging.debug(" hash value matched") else: logging.debug(" hashvalue matched")
def load_file(self, filename): p = Dataparser() p.parse_file(filename) mod = lfmod.parse_tree_interpreter(p.tree, {'yes': True, 'no': False}) s = mod.m_globals.setdefault('output_format', 'midi') s = s.lower() if s in self.g_output: self.g_output[s].set_active(True) else: # MIDI is the default format self.g_output['midi'].set_active(True) self.m_filename = filename if mod.m_globals['fileformat_version'] == 1: e = Exception("TrainingSetDlg") e.msg1 = _("Cannot read old file format") e.msg2 = _( "To convert the file to the new file format, you must open and save it in an older version of Solfege. Versions from 3.16.0 to 3.20.4 should do the job." ) raise e self.g_named_tracks.set_active(mod.m_globals.get( 'named_tracks', False)) for lesson in mod.m_blocklists.setdefault('lesson', []): # In this loop we will set the filename column of the liststore # to None if there is any problem, and set a title mentioning # the unknown filename. filename = lesson['filename'] if filename: if os.path.exists(lessonfile.uri_expand(filename)): fn = filename title = self.get_lessonfile_title(filename) else: fn = None title = _(u"«<b>%s</b>» was not found") % filename self.g_liststore.append((fn, title, lesson['count'], lesson['repeat'], lesson['delay'])) else: self.g_liststore.append( (filename, _("«%s» not found") % filename, lesson['count'], lesson['repeat'], lesson['delay'])) self.m_changed = False self.set_title(self.m_filename)
def read_session_data(datadir, is_tests, counter): if not os.path.isdir(datadir): logging.debug("read_session_data: '%s' does not exist. Returning" % datadir) return for uuid in os.listdir(datadir): if not (os.path.isdir(os.path.join(datadir, uuid)) and os.path.isfile(os.path.join(datadir, '%s_hash' % uuid))): continue # We do not add statistics for lesson files we don't have # access to. if not uuid in uuid_to_filename: continue lessonfilename = uuid_to_filename[uuid] try: fileid = self.get_fileid(lessonfilename) except self.FileNotInDB: fileid = self.insert_file(lessonfilename) # saved_hashvalue will get the hash value as solfege 3.14 (or # older) calculated when the statistics was saved. try: s = open(os.path.join(datadir, u"%s_hash" % uuid), "r").read() try: saved_hashvalue = int(s) except ValueError: saved_hashvalue = None except IOError: saved_hashvalue = None real_lessonfilename = lessonfile.uri_expand(lessonfilename) s = open(real_lessonfilename, "r").read() # Check if the lesson file in this version of solfege is equal to the # one used when saving the statistics. if hash(s) != saved_hashvalue: # header.replaces is not used when importing statistics. # This because the old statistics saved the hash value # using python standard hash function, and the function # does not return the same value on all systems. def bugfix_copy_fn(filename, subdir): """ Return the filename of the copy of the file if it exists. Return filename if not. """ d, f = os.path.split(filename) fn = os.path.join(subdir, f) if (d == 'exercises%sstandard%slesson-files' % (os.sep, os.sep) and os.path.isfile(fn)): return fn return filename def bugfix_hash_file(filename, subdir): copy_fn = bugfix_copy_fn(filename, subdir) if os.path.isfile(copy_fn): return hash(open(copy_fn, 'r').read()) return None if not (saved_hashvalue == bugfix_hash_file(real_lessonfilename, "hash-bug-workaround") or saved_hashvalue == bugfix_hash_file(real_lessonfilename, "hash-bug-workaround2")): logging.debug("Ignoring statistics for '%s' since the saved hash value does not match." % lessonfilename) continue for timestamp in os.listdir(os.path.join(datadir, uuid)): if timestamp == u"passed": continue f = open(os.path.join(datadir, uuid, timestamp), 'r') session = load(f) f.close() for correct in session.keys(): for guess in session[correct]: self.conn.execute("insert into sessions " "(fileid, timestamp, answerkey, guessed, count) " "values(?, ?, ?, ?, ?)", (fileid, timestamp, unicode(correct), unicode(guess), session[correct][guess])) self.conn.execute("insert into sessioninfo " "(fileid, timestamp, sessiontype) " "values(?, ?, ?)", (fileid, timestamp, int(bool(is_tests)))) counter += 1 callback(_("Files read: %i") % counter) if is_tests: timestamp = self.conn.execute("select timestamp from sessioninfo " "where fileid=? and sessiontype=1 " "order by -timestamp ", (fileid,)).fetchone()[0] if timestamp: if lessonfile.infocache.get(lessonfilename, "module") in ('melodicinterval', 'harmonicinterval', 'singinterval'): parserclass = lessonfile.IntervalsLessonfile else: parserclass = lessonfile.IdByNameLessonfile p = parserclass() p.parse_file(lessonfilename) self.cache_new_test_result(lessonfilename, timestamp, p.get_test_requirement(), p.get_test_num_questions()) return imp
def hash_of_lessonfile(filename): assert isinstance(filename, str) with open(lessonfile.uri_expand(filename), 'r') as f: return hash_lessonfile_text(f.read())
def export_training_set(self, export_data, export_dir, output_format, name_track_by_question): """ This function requires a program that can create WAV files from MIDI files and MP3 files from WAV. """ def delay(n, tempo): """ tempo is a dict of two integers """ track = mpd.Track() track.set_bpm(*tempo) #self.get_int('config/default_bpm')) track.note(mpd.Rat(n, 4), 80, 0) soundcard.synth.play_track(track) track_idx = 0 num = sum([x['count'] for x in export_data]) # MainWin will set this to True if the user want to cancel # the export. self.m_abort_export = False report = reportlib.Report() report.append(reportlib.Heading(1, "Exported exercises")) table = reportlib.Table() report.append(table) for lesson_info in export_data: filename = lesson_info['filename'] module = lessonfile.infocache.get(filename, 'module') if module not in self.m_teachers: self.create_teacher(module) p = self.m_teachers[module].lessonfileclass() p.parse_file(lessonfile.uri_expand(filename)) for c in range(lesson_info['count']): trackname = "track-%i" if module == 'idbyname': p.select_random_question() if p.header.lesson_heading: s = p.header.lesson_heading else: s = p.header.title table.append_row("%i" % track_idx, p.get_question().name, s) if name_track_by_question: trackname = "%s-%%i" % p.get_name() soundcard.start_export( os.path.join(export_dir, "%s.mid" % trackname % track_idx)) for n in range(lesson_info.get('repeat', 1)): p.play_question() if n != lesson_info.get('repeat', 1) - 1: if 'delay' in lesson_info: delay(lesson_info['delay'], p.get_tempo()) soundcard.end_export() elif module in ('melodicinterval', 'harmonicinterval'): t = self.m_teachers[module] t.set_lessonfile(filename) t.start_practise() t.new_question("c", "c''") t.q_status = t.QSTATUS_SOLVED try: table.append_row( "%i" % track_idx, "%s" % utils.int_to_intervalname(t.m_interval)) if name_track_by_question: trackname = "%%i-%s.mid" % utils.int_to_intervalname( t.m_interval) except AttributeError: table.append_row( "%i" % track_idx, "%s" % (" + ".join([ utils.int_to_intervalname(q, False, True) for q in t.m_question ]))) if name_track_by_question: trackname = "%%i-%s.mid" % ("+".join([ utils.int_to_intervalname(q, False, True) for q in t.m_question ])) soundcard.start_export( os.path.join(export_dir, "%s.mid" % trackname % track_idx)) for n in range(lesson_info.get('repeat', 1)): t.play_question() if n != lesson_info.get('repeat', 1) - 1: if 'delay' in lesson_info: delay(lesson_info['delay'], (self.get_int('config/default_bpm'), 4)) soundcard.end_export() else: logging.warning( "export_training_set:ignoring exercise with module='%s'", module) ##### def do_convert(from_format, to_format): """ Return False if we think the convert failed. """ app_cfg_name = "app/%s_to_%s_cmd" % (from_format, to_format) if from_format == 'midi': from_ext = 'mid' else: from_ext = from_format to_ext = to_format if not cfg.get_string(app_cfg_name): solfege.win.display_error_message2( "Config variable not defined", "The missing or empty variable was '%s'" % app_cfg_name) return False try: inout = { 'in': os.path.join( export_dir, "%s.%s" % (trackname % track_idx, from_ext)), 'out': os.path.join( export_dir, "%s.%s" % (trackname % track_idx, to_ext)) } opts = cfg.get_string(app_cfg_name + '_options').split(" ") opts = [x % inout for x in opts] # For some reasong setting the executable arg does # not work for Python 2.5.2 try: subprocess.call([cfg.get_string(app_cfg_name)] + opts) except OSError, e: raise osutils.BinaryForMediaConvertorException( app_cfg_name, cfg.get_string(app_cfg_name), e) if os.path.exists( os.path.join( export_dir, "%s.%s" % (trackname % track_idx, to_ext))): os.remove( os.path.join( export_dir, "%s.%s" % (trackname % track_idx, from_ext))) else: # This means that the program failed to generate # the WAV file. We set output_format to 'midi' # because we don't want to display this error for # every single file. output_format = 'midi' solfege.win.display_error_message2( "External program must have failed", "The file in %(from)s format was not generated from the %(to)s file as expected. Please check your setup in the preferences window (CTRL-F12)." % { 'to': to_format.upper(), 'from': from_format.upper() }) except (TypeError, KeyError): solfege.win.display_error_message2( "%(from)s to %(to)s config error", "There was a format string error. Will not generate WAV files. Please check the app/midi_to_wav_cmd config variable." % { 'from': from_format, 'to': to_format }) output_format = 'midi' return True ##### if output_format in ('mp3', 'wav', 'ogg'): do_convert('midi', 'wav') if output_format in ('mp3', 'ogg'): if not do_convert('wav', output_format): output_format = 'wav' track_idx += 1 yield 1.0 * track_idx / num if self.m_abort_export: del self.m_abort_export return
def export_training_set(self, export_data, export_dir, output_format, name_track_by_question): """ This function requires a program that can create WAV files from MIDI files and MP3 files from WAV. """ def delay(n, tempo): """ tempo is a dict of two integers """ track = mpd.Track() track.set_bpm(*tempo) # self.get_int('config/default_bpm')) track.note(mpd.Rat(n, 4), 80, 0) soundcard.synth.play_track(track) track_idx = 0 num = sum([x['count'] for x in export_data]) # MainWin will set this to True if the user want to cancel # the export. self.m_abort_export = False report = reportlib.Report() report.append(reportlib.Heading(1, "Exported exercises")) table = reportlib.Table() report.append(table) for lesson_info in export_data: filename = lesson_info['filename'] module = lessonfile.infocache.get(filename, 'module') if module not in self.m_teachers: self.create_teacher(module) p = self.m_teachers[module].lessonfileclass() p.parse_file(lessonfile.uri_expand(filename)) for c in range(lesson_info['count']): trackname = "track-%i" if module == 'idbyname': p.select_random_question() if p.header.lesson_heading: s = p.header.lesson_heading else: s = p.header.title table.append_row("%i" % track_idx, p.get_question().name, s) if name_track_by_question: trackname = "%s-%%i" % p.get_name() soundcard.start_export(os.path.join( export_dir, "%s.mid" % trackname % track_idx)) for n in range(lesson_info.get('repeat', 1)): p.play_question() if n != lesson_info.get('repeat', 1) - 1: if 'delay' in lesson_info: delay(lesson_info['delay'], p.get_tempo()) soundcard.end_export() elif module in ('melodicinterval', 'harmonicinterval'): t = self.m_teachers[module] t.set_lessonfile(filename) t.start_practise() t.new_question("c", "c''") t.q_status = t.QSTATUS_SOLVED try: table.append_row("%i" % track_idx, "%s" % utils.int_to_intervalname(t.m_interval)) if name_track_by_question: trackname = "%%i-%s.mid" % utils.int_to_intervalname(t.m_interval) except AttributeError: table.append_row("%i" % track_idx, "%s" % (" + ".join([utils.int_to_intervalname(q, False, True) for q in t.m_question]))) if name_track_by_question: trackname = "%%i-%s.mid" % ("+".join([utils.int_to_intervalname(q, False, True) for q in t.m_question])) soundcard.start_export(os.path.join( export_dir, "%s.mid" % trackname % track_idx)) for n in range(lesson_info.get('repeat', 1)): t.play_question() if n != lesson_info.get('repeat', 1) - 1: if 'delay' in lesson_info: delay(lesson_info['delay'], (self.get_int('config/default_bpm'), 4)) soundcard.end_export() else: logging.warning("export_training_set:ignoring exercise with module='%s'", module) ##### def do_convert(from_format, to_format): """ Return False if we think the convert failed. """ app_cfg_name = "app/%s_to_%s_cmd" % (from_format, to_format) if from_format == 'midi': from_ext = 'mid' else: from_ext = from_format to_ext = to_format if not cfg.get_string(app_cfg_name): solfege.win.display_error_message2("Config variable not defined", "The missing or empty variable was '%s'" % app_cfg_name) return False try: inout = { 'in': os.path.join(export_dir, "%s.%s" % (trackname % track_idx, from_ext)), 'out': os.path.join(export_dir, "%s.%s" % (trackname % track_idx, to_ext))} opts = cfg.get_string(app_cfg_name + '_options').split(" ") opts = [x % inout for x in opts] # For some reasong setting the executable arg does # not work for Python 2.5.2 try: subprocess.call( [cfg.get_string(app_cfg_name)] + opts) except OSError as e: raise osutils.BinaryForMediaConvertorException(app_cfg_name, cfg.get_string(app_cfg_name), e) if os.path.exists(os.path.join(export_dir, "%s.%s" % (trackname % track_idx, to_ext))): os.remove(os.path.join(export_dir, "%s.%s" % (trackname % track_idx, from_ext))) else: # This means that the program failed to generate # the WAV file. We set output_format to 'midi' # because we don't want to display this error for # every single file. output_format = 'midi' solfege.win.display_error_message2("External program must have failed", "The file in %(from)s format was not generated from the %(to)s file as expected. Please check your setup in the preferences window (CTRL-F12)." % {'to': to_format.upper(), 'from': from_format.upper()}) except (TypeError, KeyError): solfege.win.display_error_message2("%(from)s to %(to)s config error", "There was a format string error. Will not generate WAV files. Please check the app/midi_to_wav_cmd config variable." % {'from': from_format, 'to': to_format}) output_format = 'midi' return True ##### if output_format in ('mp3', 'wav', 'ogg'): do_convert('midi', 'wav') if output_format in ('mp3', 'ogg'): if not do_convert('wav', output_format): output_format = 'wav' track_idx += 1 yield 1.0 * track_idx / num if self.m_abort_export: del self.m_abort_export return reportlib.HtmlReport(report, os.path.join(export_dir, "toc.html"))
def hash_of_lessonfile(filename): assert isinstance(filename, unicode) return hash_lessonfile_text(open(lessonfile.uri_expand(filename), 'r').read())