def _set_audio_device_box(self): # format: "idx - device name" devices = AudioDevice().list_devices() items = [] for device in devices: index = device['index'] name = device['name'] item = str(index) + ' - ' + name items.append(item) self.ui.audioDeviceBox.addItems(items)
def __init__(self, parent=None): super().__init__(parent) # Default values. Updated if found in config.JSON self.use_qt_thread = False self.rhythm_algorithm = "multifeature" self.default_device_name = "" self.show_video_preview = True self.video_loop_bpm = 60 self.video_update_skip_ms = 100 self.limit_tempo_by_default = False self.tempo_lower_limit = 60.0 self.tempo_upper_limit = 120.0 self.screen = 0 self.spotify_track_id = "" self.read_config() self.setWindowTitle("Gandalf Enjoys Music") self.desktop = QApplication.desktop() self.audio = AudioDevice(self.default_device_name) self.input_devices = self.audio.get_input_device_names() self.audio_changed.connect(self.audio.change_audio_input) if self.use_qt_thread: self.bpm_extractor = BPMQt(self.update_bpm, algorithm=self.rhythm_algorithm) else: self.bpm_extractor = BPMmp(self.update_bpm, algorithm=self.rhythm_algorithm) self.audio.data_ready.connect(self.bpm_extractor.start_bpm_calculation) self.init_ui()
def start_recording(self): self.file_path = self._get_save_path() # initialize stream audio_device_index = self._get_audio_device_index() for device in AudioDevice().list_devices(): if device['index'] == audio_device_index: channels = device['channels'] # TODO: Now I set `channels=1` to make the audio file to be mono. # It's only for the current audio interface. It's supposed to be # variable `channels`. Also it can be improved by specifying a certain # channel of input device, and always making the audio file mono. self.recording_file = Recorder(channels=1).open( self.file_path, audio_device_index) self.recording_file.start_recording() # update objects # update the buttons' status self.is_recording = True self._update_status() # clean up any text in promptLabel self.ui.promptLabel.setText('') # start counting self.timer.start(1000)
import matplotlib.animation import numpy import threading # engine = engine_factory.v_four_90_deg() # engine = engine_factory.w_16() # engine = engine_factory.v_8_LS() # engine = engine_factory.inline_5_crossplane() # engine = engine_factory.inline_6() engine = engine_factory.boxer_4_crossplane_custom( [1, 1, 0, 0]) # (rando := random.randrange(360))) # engine = engine_factory.boxer_4_half() # engine = engine_factory.random() # engine = engine_factory.fake_rotary_2rotor() audio_device = AudioDevice() stream = audio_device.play_stream(engine.gen_audio) print('\nEngine is running...') # print(rando) RATE = 44100 BUFFER = 882 fig = plt.figure() line1 = plt.plot([], [])[0] line2 = plt.plot([], [])[0] r = range(0, int(RATE / 2 + 1), int(RATE / BUFFER)) l = len(r)
def __init__(self, logger): self.logger = logger super(MainWindow, self).__init__() self.ui = Terzpegelmesser.Ui_MainWindow() self.ui.setupUi(self) self.chunk_number = 0 self.buffer_timer_time = 0. self.cpu_percent = 0. self.setMinimumSize(1000, 600) # Initialize the audio data ring buffer self.audiobuffer = AudioBuffer(self.logger) # Initialize the audio device self.audio_device = AudioDevice(self.logger) # Initialize the blocklength self.blocklength = 2048 self.ui.BoxFFT.setCurrentIndex(6) self.logger.push("initial set Blocksize to " + str(self.blocklength)) # Initialize the frequency weighting flag self.weight = 0 # Initialize the number of samples shown in waveform monitor self.window = 128 # Initialize the number of periods shown in waveform monitor self.NumberOfPeriods = 10 # Initialize the flag for lin (0) and log (1) fft plotting self.plotflag = 1 devices = self.audio_device.get_readable_devices_list() for device in devices: self.ui.DeviceList.addItem(device) current_device = self.audio_device.get_readable_current_device() self.ui.DeviceList.setCurrentIndex(current_device) self.display_timer = QTimer() self.display_timer.setInterval(SMOOTH_DISPLAY_TIMER_PERIOD_MS) self.connect(self.display_timer, SIGNAL('timeout()'), self.update_buffer) self.connect(self.ui.ButtonStartStop, SIGNAL('triggered()'), self.stream_run) self.connect(self.ui.DeviceList, SIGNAL('currentIndexChanged(int)'), self.input_device_changed) self.connect(self.ui.BoxFFT, SIGNAL('currentIndexChanged(int)'), self.update_blocklength) self.ui.action32.triggered.connect(lambda: self.update_blocklength(0)) self.ui.action32.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(0)) self.ui.action64.triggered.connect(lambda: self.update_blocklength(1)) self.ui.action64.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(1)) self.ui.action128.triggered.connect(lambda: self.update_blocklength(2)) self.ui.action128.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(2)) self.ui.action256.triggered.connect(lambda: self.update_blocklength(3)) self.ui.action256.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(3)) self.ui.action512.triggered.connect(lambda: self.update_blocklength(4)) self.ui.action512.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(4)) self.ui.action1024.triggered.connect(lambda: self.update_blocklength( 5)) self.ui.action1024.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(5)) self.ui.action2048.triggered.connect(lambda: self.update_blocklength( 6)) self.ui.action2048.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(6)) self.ui.action4096.triggered.connect(lambda: self.update_blocklength( 7)) self.ui.action4096.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(7)) self.ui.action8192.triggered.connect(lambda: self.update_blocklength( 8)) self.ui.action8192.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(8)) self.ui.actionNone.triggered.connect(lambda: self.update_weight(0)) self.ui.actionNone.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(0)) self.ui.actionA.triggered.connect(lambda: self.update_weight(1)) self.ui.actionA.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(1)) self.ui.actionC.triggered.connect(lambda: self.update_weight(2)) self.ui.actionC.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(2)) self.connect(self.ui.BoxBew, SIGNAL('currentIndexChanged(int)'), self.update_weight) self.connect(self.ui.RadioLin, SIGNAL("clicked()"), self.update_plotflag_lin) self.connect(self.ui.RadioLog, SIGNAL("clicked()"), self.update_plotflag_log) self.ui.actionLogarithmic.triggered.connect(self.update_plotflag_log) self.ui.actionLogarithmic.triggered.connect( lambda: self.ui.RadioLog.setChecked(True)) self.ui.actionLinear.triggered.connect(self.update_plotflag_lin) self.ui.actionLinear.triggered.connect( lambda: self.ui.RadioLin.setChecked(True)) self.connect(self.ui.push_plus, SIGNAL("clicked()"), self.update_NumberOfPeriods_minus) self.ui.actionZoom_Out.triggered.connect( self.update_NumberOfPeriods_plus) self.connect(self.ui.push_minus, SIGNAL("clicked()"), self.update_NumberOfPeriods_plus) self.ui.actionZoom_In.triggered.connect( self.update_NumberOfPeriods_minus) self.gain_plotter = ( gain_plotter.Gain_Plotter(self.ui.PlotGainVerlauf, self.audiobuffer)) self.spektro_plotter = ( third_octave_plotter.SpektroPlotter(self.ui.PlotTerzpegel, self.audiobuffer)) self.waveform = waveform.Oszi(self.ui.PlotWellenform, self.audiobuffer, self.NumberOfPeriods) self.channelplotter = ( channel_plotter.ChannelPlotter(self.ui.PlotKanalpegel, self.audiobuffer)) self.specgramplot = ( spectrogram_plotter.Spectrogram_Plot(self.ui.PlotSpektrogramm, self.audiobuffer)) self.spektro_plotter_2 = ( third_octave_plotter.SpektroPlotter(self.ui.PlotTerzpegel_2, self.audiobuffer)) self.fft_plot = fft_plotter.FFTPlotter(self.ui.PlotFFT, self.audiobuffer, self.blocklength, self.plotflag) # if the startStop button is clicked, the timer starts and the stream is # filled with acoustic data self.ui.ButtonStartStop.clicked.connect(self.stream_run) self.ui.ButtonStartStop.state = 0 self.display_timer.timeout.connect(self.update_plot)
class MainWindow(QMainWindow): def __init__(self, logger): self.logger = logger super(MainWindow, self).__init__() self.ui = Terzpegelmesser.Ui_MainWindow() self.ui.setupUi(self) self.chunk_number = 0 self.buffer_timer_time = 0. self.cpu_percent = 0. self.setMinimumSize(1000, 600) # Initialize the audio data ring buffer self.audiobuffer = AudioBuffer(self.logger) # Initialize the audio device self.audio_device = AudioDevice(self.logger) # Initialize the blocklength self.blocklength = 2048 self.ui.BoxFFT.setCurrentIndex(6) self.logger.push("initial set Blocksize to " + str(self.blocklength)) # Initialize the frequency weighting flag self.weight = 0 # Initialize the number of samples shown in waveform monitor self.window = 128 # Initialize the number of periods shown in waveform monitor self.NumberOfPeriods = 10 # Initialize the flag for lin (0) and log (1) fft plotting self.plotflag = 1 devices = self.audio_device.get_readable_devices_list() for device in devices: self.ui.DeviceList.addItem(device) current_device = self.audio_device.get_readable_current_device() self.ui.DeviceList.setCurrentIndex(current_device) self.display_timer = QTimer() self.display_timer.setInterval(SMOOTH_DISPLAY_TIMER_PERIOD_MS) self.connect(self.display_timer, SIGNAL('timeout()'), self.update_buffer) self.connect(self.ui.ButtonStartStop, SIGNAL('triggered()'), self.stream_run) self.connect(self.ui.DeviceList, SIGNAL('currentIndexChanged(int)'), self.input_device_changed) self.connect(self.ui.BoxFFT, SIGNAL('currentIndexChanged(int)'), self.update_blocklength) self.ui.action32.triggered.connect(lambda: self.update_blocklength(0)) self.ui.action32.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(0)) self.ui.action64.triggered.connect(lambda: self.update_blocklength(1)) self.ui.action64.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(1)) self.ui.action128.triggered.connect(lambda: self.update_blocklength(2)) self.ui.action128.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(2)) self.ui.action256.triggered.connect(lambda: self.update_blocklength(3)) self.ui.action256.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(3)) self.ui.action512.triggered.connect(lambda: self.update_blocklength(4)) self.ui.action512.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(4)) self.ui.action1024.triggered.connect(lambda: self.update_blocklength( 5)) self.ui.action1024.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(5)) self.ui.action2048.triggered.connect(lambda: self.update_blocklength( 6)) self.ui.action2048.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(6)) self.ui.action4096.triggered.connect(lambda: self.update_blocklength( 7)) self.ui.action4096.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(7)) self.ui.action8192.triggered.connect(lambda: self.update_blocklength( 8)) self.ui.action8192.triggered.connect( lambda: self.ui.BoxFFT.setCurrentIndex(8)) self.ui.actionNone.triggered.connect(lambda: self.update_weight(0)) self.ui.actionNone.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(0)) self.ui.actionA.triggered.connect(lambda: self.update_weight(1)) self.ui.actionA.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(1)) self.ui.actionC.triggered.connect(lambda: self.update_weight(2)) self.ui.actionC.triggered.connect( lambda: self.ui.BoxBew.setCurrentIndex(2)) self.connect(self.ui.BoxBew, SIGNAL('currentIndexChanged(int)'), self.update_weight) self.connect(self.ui.RadioLin, SIGNAL("clicked()"), self.update_plotflag_lin) self.connect(self.ui.RadioLog, SIGNAL("clicked()"), self.update_plotflag_log) self.ui.actionLogarithmic.triggered.connect(self.update_plotflag_log) self.ui.actionLogarithmic.triggered.connect( lambda: self.ui.RadioLog.setChecked(True)) self.ui.actionLinear.triggered.connect(self.update_plotflag_lin) self.ui.actionLinear.triggered.connect( lambda: self.ui.RadioLin.setChecked(True)) self.connect(self.ui.push_plus, SIGNAL("clicked()"), self.update_NumberOfPeriods_minus) self.ui.actionZoom_Out.triggered.connect( self.update_NumberOfPeriods_plus) self.connect(self.ui.push_minus, SIGNAL("clicked()"), self.update_NumberOfPeriods_plus) self.ui.actionZoom_In.triggered.connect( self.update_NumberOfPeriods_minus) self.gain_plotter = ( gain_plotter.Gain_Plotter(self.ui.PlotGainVerlauf, self.audiobuffer)) self.spektro_plotter = ( third_octave_plotter.SpektroPlotter(self.ui.PlotTerzpegel, self.audiobuffer)) self.waveform = waveform.Oszi(self.ui.PlotWellenform, self.audiobuffer, self.NumberOfPeriods) self.channelplotter = ( channel_plotter.ChannelPlotter(self.ui.PlotKanalpegel, self.audiobuffer)) self.specgramplot = ( spectrogram_plotter.Spectrogram_Plot(self.ui.PlotSpektrogramm, self.audiobuffer)) self.spektro_plotter_2 = ( third_octave_plotter.SpektroPlotter(self.ui.PlotTerzpegel_2, self.audiobuffer)) self.fft_plot = fft_plotter.FFTPlotter(self.ui.PlotFFT, self.audiobuffer, self.blocklength, self.plotflag) # if the startStop button is clicked, the timer starts and the stream is # filled with acoustic data self.ui.ButtonStartStop.clicked.connect(self.stream_run) self.ui.ButtonStartStop.state = 0 self.display_timer.timeout.connect(self.update_plot) def update_plot(self): isvis_FFT = self.ui.PlotFFT.isVisible() self.channelplotter.plot() self.gain_plotter.plot() self.spektro_plotter.plot(self.weight) self.spektro_plotter_2.plot(self.weight) self.waveform.plot(self.NumberOfPeriods) if isvis_FFT == False: self.specgramplot.plotspecgram() if isvis_FFT == True: self.fft_plot.plot(self.blocklength, self.plotflag) # opens stream if there is none, else closes it def stream_run(self): if self.ui.ButtonStartStop.state == 0: #openstream() self.logger.push("Timer start") self.display_timer.start() self.ui.ButtonStartStop.setText("Stop") self.display_timer.start() print(logger.log) self.ui.ButtonStartStop.state = 1 else: #closestream() self.logger.push("Timer stop") self.display_timer.stop() self.ui.ButtonStartStop.setText("Start") self.display_timer.stop() self.ui.ButtonStartStop.state = 0 print(logger.log) def update_buffer(self): chunks, t, newpoints = ( self.audio_device.update(self.audiobuffer.ringbuffer)) self.audiobuffer.set_newdata(newpoints) self.chunk_number += chunks self.buffer_timer_time = (95. * self.buffer_timer_time + 5. * t) / 100. def update_blocklength(self, newblocklength): self.blocklength = 32 * (2 ** newblocklength) self.logger.push("Blocksize changed to " + str(self.blocklength)) print(logger.log) self.fft_plot.must_plot = True def update_NumberOfPeriods_plus(self): self.NumberOfPeriods += 1 self.logger.push("Desired number of periods: " + str(self.NumberOfPeriods)) print(logger.log) def update_NumberOfPeriods_minus(self): self.NumberOfPeriods -= 1 # sets lower limit of self.NumberOfPeriods to 1 if self.NumberOfPeriods < 1: self.NumberOfPeriods = 1 self.logger.push("Desired number of periods: " + str(self.NumberOfPeriods)) print(logger.log) def update_weight(self, weight): self.weight = weight if self.weight == 0: self.logger.push("Using Z Curve (unweighted)") print(logger.log) elif self.weight == 1: self.logger.push("Using A Curve") print(logger.log) elif self.weight == 2: self.logger.push("Using C Curve") print(logger.log) else: print self.weight def update_plotflag_lin(self): self.plotflag = 0 self.logger.push("Linear frequency axis selected") self.fft_plot.must_plot = True print(logger.log) def update_plotflag_log(self): self.plotflag = 1 self.logger.push("Logarithmic frequency axis selected") self.fft_plot.must_plot = True print(logger.log) def input_device_changed(self, index): success, index = self.audio_device.select_input_device(index) self.ui.DeviceList.setCurrentIndex(index) self.fft_plot.must_plot = True if not success: # Note: the error message is a child of the settings dialog, so that # that dialog remains on top when the error message is closed error_message = QErrorMessage(self.settings_dialog) error_message.setWindowTitle("Input device error") error_message.showMessage("Impossible to use the selected input" " device, reverting to the previous one") def statistics(self): if not self.about_dialog.LabelStats.isVisible(): return label = "Chunk #%d\n"\ "Audio buffer retrieval: %.02f ms\n"\ "Global CPU usage: %d %%\n"\ "Number of overflowed inputs (XRUNs): %d"\ % (self.chunk_number, self.buffer_timer_time, self.cpu_percent, self.audio_device.xruns) self.about_dialog.LabelStats.setText(label)
class MainWindow(QMainWindow): """Display video loop and controls""" audio_changed = Signal(str) def __init__(self, parent=None): super().__init__(parent) # Default values. Updated if found in config.JSON self.use_qt_thread = False self.rhythm_algorithm = "multifeature" self.default_device_name = "" self.show_video_preview = True self.video_loop_bpm = 60 self.video_update_skip_ms = 100 self.limit_tempo_by_default = False self.tempo_lower_limit = 60.0 self.tempo_upper_limit = 120.0 self.screen = 0 self.spotify_track_id = "" self.read_config() self.setWindowTitle("Gandalf Enjoys Music") self.desktop = QApplication.desktop() self.audio = AudioDevice(self.default_device_name) self.input_devices = self.audio.get_input_device_names() self.audio_changed.connect(self.audio.change_audio_input) if self.use_qt_thread: self.bpm_extractor = BPMQt(self.update_bpm, algorithm=self.rhythm_algorithm) else: self.bpm_extractor = BPMmp(self.update_bpm, algorithm=self.rhythm_algorithm) self.audio.data_ready.connect(self.bpm_extractor.start_bpm_calculation) self.init_ui() def init_ui(self): dir_path = os.path.dirname(os.path.realpath(__file__)) file_location = dir_path + "/resources/gandalf_icon_256px.png" self.icon_pixmap = QPixmap(file_location) self.icon = QIcon(self.icon_pixmap) self.setWindowIcon(self.icon) self.setWindowIconText("Gandalf Enjoys Music") self.central = QWidget(self) self.setCentralWidget(self.central) self.layout = QVBoxLayout() self.lock_checkbox = QCheckBox("Manual tempo", self) self.lock_checkbox.clicked.connect(self.update_lock_checkbox) self.limit_layout = QVBoxLayout() self.limit_checkbox = QCheckBox("Limit tempo between:", self) self.limit_checkbox.setChecked(self.limit_tempo_by_default) self.limit_checkbox.clicked.connect(self.update_bpm_manually) self.init_video() if self.show_video_preview: self.setFixedSize(QSize(500, 350)) self.layout.addWidget(self.video_widget) else: self.setFixedSize(500, 100) self.fullscreen_button = QPushButton(self) self.fullscreen_button.setText("Go Fullscreen") self.layout.addWidget(self.fullscreen_button) self.fullscreen_button.clicked.connect(self.show_fullscreen) self.video_widget.fullscreen_changed.connect( self.update_button_text) self.video_widget.fullscreen_changed.connect( self.reset_video_position ) self.tempo_control_layout = QVBoxLayout() self.tempo_control_layout.addWidget(self.lock_checkbox) self.set_bpm_widget = QLineEdit("{:.1f}".format(self.old_bpm), self) self.set_bpm_widget.setMaxLength(5) self.set_bpm_widget.returnPressed.connect(self.update_bpm_manually) self.set_bpm_palette = QPalette() self.set_bpm_palette.setColor(QPalette.Text, Qt.gray) self.set_bpm_widget.setPalette(self.set_bpm_palette) self.set_bpm_widget.setFixedWidth(50) self.tempo_control_layout.addWidget(self.set_bpm_widget) self.limit_layout.addWidget(self.limit_checkbox) self.limits = QHBoxLayout() self.lower_bpm_widget = QLineEdit(str(self.tempo_lower_limit), self) self.lower_bpm_widget.setMaxLength(5) self.lower_bpm_widget.returnPressed.connect(self.update_lower_limit) self.lower_bpm_widget.setFixedWidth(50) self.limits.addWidget(self.lower_bpm_widget) self.upper_bpm_widget = QLineEdit(str(self.tempo_upper_limit), self) self.upper_bpm_widget.setMaxLength(5) self.upper_bpm_widget.returnPressed.connect(self.update_upper_limit) self.upper_bpm_widget.setFixedWidth(50) self.limits.addWidget(self.upper_bpm_widget) self.limit_layout.addLayout(self.limits) self.control_layout = QHBoxLayout() self.control_layout.addLayout(self.tempo_control_layout) self.control_layout.addLayout(self.limit_layout) self.save_settings_button = QPushButton("Save settings", self) self.save_settings_button.clicked.connect(self.save_config) self.control_layout.addWidget(self.save_settings_button) self.layout.addLayout(self.control_layout) self.device_layout = QHBoxLayout() self.audio_select_label = QLabel("Audio device:", self) self.device_layout.addWidget(self.audio_select_label) self.audio_selection = QComboBox(self) self.audio_selection.addItems(self.input_devices) self.audio_selection.currentIndexChanged.connect(self.audio_selection_changed) self.device_layout.addWidget(self.audio_selection) self.layout.addLayout(self.device_layout) self.central.setLayout(self.layout) def init_video(self): self.old_bpm = 1.0 self.video_widget = VideoWidget(self, self.show_video_preview, self.screen) self.media_player = QMediaPlayer(self.central) self.media_player.setVideoOutput(self.video_widget) self.playlist = QMediaPlaylist(self.media_player) dir_path = os.path.dirname(os.path.realpath(__file__)) file_location = dir_path + "/resources/video_long.mp4" self.video_file = QUrl.fromLocalFile(file_location) self.playlist.addMedia(self.video_file) self.playlist.setPlaybackMode(QMediaPlaylist.Loop) self.playlist.setCurrentIndex(0) self.media_player.setPlaylist(self.playlist) self.media_player.mediaStatusChanged.connect(self.handle_media_state_changed) self.media_player.play() self.change_playback_rate(self.video_loop_bpm) if not self.show_video_preview: self.video_widget.hide() def handle_media_state_changed(self, state): if state == QMediaPlayer.MediaStatus.BufferedMedia: playback_speed = self.old_bpm / self.video_loop_bpm self.media_player.setPlaybackRate(playback_speed) self.media_player.setPosition(0) def change_playback_rate(self, bpm): """Update playback speed for video loop.""" if bpm != self.old_bpm: # Prevent switching between double and half tempo during the same song in spotify track_id = get_spotify_track() if not self.lock_checkbox.isChecked()\ and not self.limit_checkbox.isChecked()\ and (math.isclose(bpm*2,self.old_bpm, rel_tol=3e-2)\ or math.isclose(bpm, self.old_bpm*2, rel_tol=3e-2))\ and track_id and track_id == self.spotify_track_id: self.spotify_track_id = track_id return self.spotify_track_id = track_id self.old_bpm = bpm playback_speed = bpm / self.video_loop_bpm # Workaround for a bug which causes irregular video playback speed # after changing playback rate current_position = self.media_player.position() self.media_player.setPlaybackRate(playback_speed) self.media_player.setPosition(current_position + self.video_update_skip_ms * playback_speed) def update_bpm(self, bpm, manual=False): if not manual: if self.lock_checkbox.isChecked(): return bpm = float(int(bpm+0.5)) if self.limit_checkbox.isChecked(): while bpm < self.tempo_lower_limit: bpm = bpm * 2.0 while bpm > self.tempo_upper_limit: bpm = bpm / 2.0 self.change_playback_rate(bpm) self.set_bpm_widget.setText("{:.1f}".format(self.old_bpm)) def update_bpm_manually(self): bpm = self.set_bpm_widget.text() try: bpm = float(bpm) if bpm < 1.0: raise ValueError except ValueError: return self.spotify_track_id = "" self.update_bpm(bpm, manual=True) def update_lock_checkbox(self): if self.lock_checkbox.isChecked(): self.set_bpm_palette = QPalette() self.set_bpm_palette.setColor(QPalette.Text, Qt.black) self.set_bpm_widget.setPalette(self.set_bpm_palette) self.set_bpm_widget.setReadOnly(False) else: self.set_bpm_palette = QPalette() self.set_bpm_palette.setColor(QPalette.Text, Qt.gray) self.set_bpm_widget.setPalette(self.set_bpm_palette) self.set_bpm_widget.setReadOnly(True) def update_lower_limit(self, value=None): if not value: value = self.lower_bpm_widget.text() try: value = float(value) if value < 1.0: raise ValueError except ValueError: return if value <= self.tempo_upper_limit / 2.0: self.tempo_lower_limit = value else: self.tempo_lower_limit = self.tempo_upper_limit / 2.0 self.lower_bpm_widget.setText("{:.1f}".format(self.tempo_lower_limit)) def update_upper_limit(self, value=None): if not value: value = self.upper_bpm_widget.text() try: value = float(value) if value < 1.0: raise ValueError except ValueError: return if value >= self.tempo_lower_limit * 2.0: self.tempo_upper_limit = value else: self.tempo_upper_limit = self.tempo_lower_limit * 2.0 self.upper_bpm_widget.setText("{:.1f}".format(self.tempo_upper_limit)) def audio_selection_changed(self, idx): self.audio_changed.emit(self.audio_selection.currentText()) @Slot() def show_fullscreen(self): self.reset_video_position() if self.video_widget.isFullScreen(): self.video_widget.hide() self.fullscreen_button.setText("Go Fullscreen") else: self.video_widget.setFullScreen(True) self.video_widget.setGeometry(self.desktop.screenGeometry(self.screen)) self.fullscreen_button.setText("Hide Fullscreen") @Slot() def reset_video_position(self): self.media_player.setPosition(0) @Slot(bool) def update_button_text(self, fullscreen_status): if fullscreen_status: self.fullscreen_button.setText("Hide Fullscreen") else: self.fullscreen_button.setText("Go Fullscreen") def read_config(self): with open("config.JSON") as config_file: config = json.load(config_file) if "no_multiprocess" in config: self.use_qt_thread = config["no_multiprocess"] if config.get("rhythm_algorithm_faster"): self.rhythm_algorithm = "degara" if config.get("default_device"): self.default_device_name = config["default_device"] if "show_video_preview" in config: self.show_video_preview = config.get("show_video_preview") if config.get("video_loop_bpm"): self.video_loop_bpm = config["video_loop_bpm"] if config.get("video_update_skip_time_ms"): self.video_update_skip_ms = config["video_update_skip_time_ms"] if config.get("limit_tempo_by_default"): self.limit_tempo_by_default = config["limit_tempo_by_default"] if config.get("tempo_lower_limit"): self.tempo_lower_limit = config["tempo_lower_limit"] if config.get("tempo_upper_limit"): self.tempo_upper_limit = config["tempo_upper_limit"] if "screen" in config: self.screen = config["screen"] @Slot() def save_config(self): fast_rhythm_algo = self.rhythm_algorithm == "degara" data = { "no_multiprocess": self.use_qt_thread, "rhythm_algorithm_faster": fast_rhythm_algo, "default_device": self.audio_selection.currentText(), "show_video_preview": self.show_video_preview, "video_loop_bpm": self.video_loop_bpm, "video_update_skip_time_ms": self.video_update_skip_ms, "limit_tempo_by_default": self.limit_checkbox.isChecked(), "tempo_lower_limit": self.tempo_lower_limit, "tempo_upper_limit": self.tempo_upper_limit, "screen": self.screen } with open("config.JSON", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=4)