示例#1
0
    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
            )
示例#2
0
    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
        )
示例#3
0
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"))
        )