def reset_labels(self): # Clear old labels for i in reversed(range(self.labels_layout.count())): self.labels_layout.itemAt(i).widget().setParent(None) self.labels = list() # Create new labels for i in range(self.exercise.get_voice_length()): self.labels.append(PictureLabel( picture_path='graphics/pitches2.png', max_markers=self.exercise.get_chord_size() )) # Attach events to labels for i in range(len(self.labels)): self.labels[i].set_move_event(self.move_event, i) self.labels[i].set_left_click_event(self.left_click_event, i) self.labels[i].set_right_click_event(self.right_click_event, i) # Attach labels to layout for i in range(len(self.labels)): self.labels_layout.addWidget( self.labels[i], i, 0, alignment=QtCore.Qt.AlignCenter )
def __init__(self): # Add exercise class self.exercise = IntervalsExercise( sampling_frequency=44100 ) # === INSTRUCTION WINDOW === self.instruction_window = ExerciseInstructionWindow( instruction="\n\n\ In this exercise your task is to recognise the length of the interval you hear.\n\n\ After pressing \"Generate New Interval\" button an interval will be played.\n\n\ Using your mouse click on the black scale in such a place that the correct length is between\n\ cyan lines. Then the correct answer will appear in green, if you answered correctly, or in red,\n\ if you failed.\ ", back_button_name="back_from_instruction_button", forward_button_name="forward_from_instruction_button", button_method=self.make_handleButton ) # === MAIN WINDOW === self.main_window = ExerciseMainWindow() # Add picture self.central_widget = QtWidgets.QWidget(self.main_window) self.label = PictureLabel('graphics/intervals1.png') self.main_window.grid_layout.addWidget( self.label, 0, 0, 1, 7, QtCore.Qt.AlignCenter ) self.label.set_move_event(self.move_event) self.label.set_left_click_event(self.press_event) # Add button to main page self.main_window.add_button( name="back_button", position=0, size=1, text="Back", method=self.make_handleButton ) # Add state label self.main_window.add_state_label( text="Press button to generate new example -->", position=1, size=3 ) # Add action button self.main_window.add_button( name="action_button", position=4, size=1, text="Generate New Interval", method=self.make_handleButton ) # Add button to settings page self.main_window.add_button( name="settings_button", position=5, size=1, text="Exercise Settings", method=self.make_handleButton ) # Add button to generator page self.main_window.add_button( name="generator_button", position=6, size=1, text="Sound Generator", method=self.make_handleButton ) # === GENERATOR SETTINGS WINDOW === self.generator_window = ExerciseSettingsWindow() # Add volume setting self.generator_window.add_setting( name="volume", text="Volume:", values=[ "0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0" ], default_option_index=10, setting_method=self.volume_changed ) # Add synthesizer type setting self.generator_window.add_setting( name="synthesizer_type", text="Synthesizer Type:", values=[ "Sine", "Saw", "Triangle", "Square", "Noise" ], default_option_index=2, setting_method=self.synthesizer_type_changed ) # Add sampling frequency setting self.generator_window.add_setting( name="sampling_frequency", text="Sampling Frequency:", values=[ "8000", "16000", "22050", "44100", "48000", "96000", "192000" ], default_option_index=3, setting_method=self.sampling_frequency_changed ) # Add play type setting self.generator_window.add_setting( name="play_type", text="Play Type:", values=[ "Upwards", "Downwards", "Upwards with hold", "Downwards with hold", "Together" ], default_option_index=0, setting_method=self.play_type_changed ) # Add button to intervals page self.generator_window.add_button( name="back_from_generator", text="Back", button_method=self.make_handleButton ) # === EXERCISE SETTINGS WINDOW === self.setting_window = ExerciseSettingsWindow() # Add scale setting self.setting_window.add_setting( name="scale", text="Scale:", values=[ "12-TET (A=440Hz)", "24-TET (A=440Hz)", "31-TET (A=440Hz)", "Pythagorean (C-based) (A=440Hz)", "Just (C-based) (A=440Hz)", "Quarter-comma meantone (C-based) (A=440Hz)", "Bach's (Werckmeister III) (A=440Hz)" ], default_option_index=0, setting_method=self.scale_changed ) # Add lowest pitch setting self.setting_window.add_setting( name="lowest_pitch", text="Lowest Pitch:", values=[ "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8" ], default_option_index=0, setting_method=self.lowest_pitch_changed ) # Add highest pitch setting self.setting_window.add_setting( name="highest_pitch", text="Highest Pitch:", values=[ "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9" ], default_option_index=4, setting_method=self.highest_pitch_changed ) # Add smallest interval setting self.setting_window.add_setting( name="smallest_interval", text="Smallest Interval:", values=[ "0", "400", "700", "1200", "1900", ], default_option_index=0, setting_method=self.smallest_interval_changed ) # Add largest interval setting self.setting_window.add_setting( name="largest_interval", text="Largest Interval:", values=[ "400", "700", "1200", "1900", "2400" ], default_option_index=2, setting_method=self.largest_interval_changed ) # Add possible detune setting self.setting_window.add_setting( name="possible_detune", text="Possible Detune:", values=[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" ], default_option_index=1, setting_method=self.possible_detune_changed ) # Add possible detune setting self.setting_window.add_setting( name="possible_error", text="Possible Error:", values=[ "5", "10", "20", "50", "100", "200", "500", "1000", "2000" ], default_option_index=2, setting_method=self.possible_error_changed ) # Add button to intervals page self.setting_window.add_button( name="back_from_settings", text="Back", button_method=self.make_handleButton )
class IntervalsWindow(): def __init__(self): # Add exercise class self.exercise = IntervalsExercise( sampling_frequency=44100 ) # === INSTRUCTION WINDOW === self.instruction_window = ExerciseInstructionWindow( instruction="\n\n\ In this exercise your task is to recognise the length of the interval you hear.\n\n\ After pressing \"Generate New Interval\" button an interval will be played.\n\n\ Using your mouse click on the black scale in such a place that the correct length is between\n\ cyan lines. Then the correct answer will appear in green, if you answered correctly, or in red,\n\ if you failed.\ ", back_button_name="back_from_instruction_button", forward_button_name="forward_from_instruction_button", button_method=self.make_handleButton ) # === MAIN WINDOW === self.main_window = ExerciseMainWindow() # Add picture self.central_widget = QtWidgets.QWidget(self.main_window) self.label = PictureLabel('graphics/intervals1.png') self.main_window.grid_layout.addWidget( self.label, 0, 0, 1, 7, QtCore.Qt.AlignCenter ) self.label.set_move_event(self.move_event) self.label.set_left_click_event(self.press_event) # Add button to main page self.main_window.add_button( name="back_button", position=0, size=1, text="Back", method=self.make_handleButton ) # Add state label self.main_window.add_state_label( text="Press button to generate new example -->", position=1, size=3 ) # Add action button self.main_window.add_button( name="action_button", position=4, size=1, text="Generate New Interval", method=self.make_handleButton ) # Add button to settings page self.main_window.add_button( name="settings_button", position=5, size=1, text="Exercise Settings", method=self.make_handleButton ) # Add button to generator page self.main_window.add_button( name="generator_button", position=6, size=1, text="Sound Generator", method=self.make_handleButton ) # === GENERATOR SETTINGS WINDOW === self.generator_window = ExerciseSettingsWindow() # Add volume setting self.generator_window.add_setting( name="volume", text="Volume:", values=[ "0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0" ], default_option_index=10, setting_method=self.volume_changed ) # Add synthesizer type setting self.generator_window.add_setting( name="synthesizer_type", text="Synthesizer Type:", values=[ "Sine", "Saw", "Triangle", "Square", "Noise" ], default_option_index=2, setting_method=self.synthesizer_type_changed ) # Add sampling frequency setting self.generator_window.add_setting( name="sampling_frequency", text="Sampling Frequency:", values=[ "8000", "16000", "22050", "44100", "48000", "96000", "192000" ], default_option_index=3, setting_method=self.sampling_frequency_changed ) # Add play type setting self.generator_window.add_setting( name="play_type", text="Play Type:", values=[ "Upwards", "Downwards", "Upwards with hold", "Downwards with hold", "Together" ], default_option_index=0, setting_method=self.play_type_changed ) # Add button to intervals page self.generator_window.add_button( name="back_from_generator", text="Back", button_method=self.make_handleButton ) # === EXERCISE SETTINGS WINDOW === self.setting_window = ExerciseSettingsWindow() # Add scale setting self.setting_window.add_setting( name="scale", text="Scale:", values=[ "12-TET (A=440Hz)", "24-TET (A=440Hz)", "31-TET (A=440Hz)", "Pythagorean (C-based) (A=440Hz)", "Just (C-based) (A=440Hz)", "Quarter-comma meantone (C-based) (A=440Hz)", "Bach's (Werckmeister III) (A=440Hz)" ], default_option_index=0, setting_method=self.scale_changed ) # Add lowest pitch setting self.setting_window.add_setting( name="lowest_pitch", text="Lowest Pitch:", values=[ "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8" ], default_option_index=0, setting_method=self.lowest_pitch_changed ) # Add highest pitch setting self.setting_window.add_setting( name="highest_pitch", text="Highest Pitch:", values=[ "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9" ], default_option_index=4, setting_method=self.highest_pitch_changed ) # Add smallest interval setting self.setting_window.add_setting( name="smallest_interval", text="Smallest Interval:", values=[ "0", "400", "700", "1200", "1900", ], default_option_index=0, setting_method=self.smallest_interval_changed ) # Add largest interval setting self.setting_window.add_setting( name="largest_interval", text="Largest Interval:", values=[ "400", "700", "1200", "1900", "2400" ], default_option_index=2, setting_method=self.largest_interval_changed ) # Add possible detune setting self.setting_window.add_setting( name="possible_detune", text="Possible Detune:", values=[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" ], default_option_index=1, setting_method=self.possible_detune_changed ) # Add possible detune setting self.setting_window.add_setting( name="possible_error", text="Possible Error:", values=[ "5", "10", "20", "50", "100", "200", "500", "1000", "2000" ], default_option_index=2, setting_method=self.possible_error_changed ) # Add button to intervals page self.setting_window.add_button( name="back_from_settings", text="Back", button_method=self.make_handleButton ) def reset_window(self): self.main_window.reset_window() self.label.if_active = False def make_handleButton(self, button): def handleButton(): if button == "settings_button": self.main_window.goto("intervals_settings_page") elif button == "generator_button": self.main_window.goto("intervals_generator_page") elif button == "back_from_instruction_button": self.instruction_window.goto("main_page") elif button == "forward_from_instruction_button": self.instruction_window.goto("intervals_page") elif button == "back_button": self.label.if_active = False self.main_window.goto("main_page") elif button == "back_from_generator": self.generator_window.goto("intervals_page") elif button == "back_from_settings": self.reset_window() self.setting_window.goto("intervals_page") elif button == "action_button": if not self.label.if_active: # Reset label self.label.reset() self.main_window.state_label.change_text( "Click near correct values on figure above" ) # Create new example self.exercise.generate_new_example() self.exercise.play_example() self.main_window.buttons["action_button"].change_text("Listen Again") elif self.label.if_active: self.exercise.play_example() return handleButton def move_event(self, x, y): self.label.mark_max_error(x, self.exercise.get_possible_error()/2) def press_event(self, x, y): answer = 2*(x - 10) if_correct, true_value = self.exercise.answer_example( answer ) if if_correct: self.main_window.state_label.change_text( "CORRECT! Pressed: "\ + "{:.2f}".format(answer)\ + "±"\ + str(int(self.exercise.get_possible_error()))\ + "c, Real value: "\ + "{:.2f}".format(true_value)\ + "c" ) else: self.main_window.state_label.change_text( "WRONG :c Pressed: "\ + "{:.2f}".format(answer)\ + "±"\ + str(int(self.exercise.get_possible_error()))\ + "c, Real value: "\ + "{:.2f}".format(true_value)\ + "c" ) self.main_window.buttons["action_button"].reset_text() self.label.mark_correct_answer(if_correct, true_value/2 + 10) # === EXERCISE GENERATOR METHODS === def volume_changed(self): self.exercise.set_volume( float(self.generator_window.get_setting("volume")) ) def synthesizer_type_changed(self): if self.generator_window.get_setting("synthesizer_type") == "Sine": self.exercise.set_synthesizer( SineSynthesizer ) elif self.generator_window.get_setting("synthesizer_type") == "Saw": self.exercise.set_synthesizer( SawSynthesizer ) elif self.generator_window.get_setting("synthesizer_type") == "Triangle": self.exercise.set_synthesizer( TriangleSynthesizer ) elif self.generator_window.get_setting("synthesizer_type") == "Square": self.exercise.set_synthesizer( SquareSynthesizer ) elif self.generator_window.get_setting("synthesizer_type") == "Noise": self.exercise.set_synthesizer( NoiseSynthesizer ) else: raise RuntimeError( '[IntervalsGeneratorWindow::synthesizer_type_changed()] Unknown synthesizer "'\ + self.generator_window.get_setting("synthesizer_type")\ + '"!' ) def sampling_frequency_changed(self): self.exercise.set_sampling_frequency( int(self.generator_window.get_setting("sampling_frequency")) ) def play_type_changed(self): self.exercise.set_play_type( self.generator_window.get_setting("play_type") ) # === EXERCISE SETTINGS METHODS === def scale_changed(self): self.exercise.set_scale( Scale(self.setting_window.get_setting("scale")) ) def lowest_pitch_changed(self): self.exercise.set_lowest_pitch( Pitch.from_name(self.setting_window.get_setting("lowest_pitch")) ) def highest_pitch_changed(self): self.exercise.set_highest_pitch( Pitch.from_name(self.setting_window.get_setting("highest_pitch")) ) def smallest_interval_changed(self): self.exercise.set_smallest_interval( Interval.from_cents( int(self.setting_window.get_setting("smallest_interval")) ) ) def largest_interval_changed(self): self.exercise.set_largest_interval( Interval.from_cents( int(self.setting_window.get_setting("largest_interval")) ) ) def possible_detune_changed(self): self.exercise.set_possible_detune( int(self.setting_window.get_setting("possible_detune")) ) def possible_error_changed(self): self.exercise.set_possible_error( int(self.setting_window.get_setting("possible_error")) )