Add (optional) GUI
This commit is contained in:
		
							
								
								
									
										205
									
								
								git-sound.py
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								git-sound.py
									
									
									
									
									
								
							| @@ -110,6 +110,208 @@ def get_file_sha(commit, file_name): | ||||
|     return t.hexsha | ||||
|  | ||||
|  | ||||
| class GitSoundWindow(object): | ||||
|     def __init__(self): | ||||
|         import gi | ||||
|         gi.require_version('Gtk', '3.0') | ||||
|  | ||||
|         from gi.repository import Gtk | ||||
|         self.Gtk = Gtk | ||||
|  | ||||
|         from gi.repository import GLib | ||||
|         self.GLib = GLib | ||||
|  | ||||
|         self.builder = self.Gtk.Builder() | ||||
|         self.builder.add_from_file('git-sound.ui') | ||||
|  | ||||
|         self.play_button = self.builder.get_object('play-button') | ||||
|         self.stop_button = self.builder.get_object('stop-button') | ||||
|  | ||||
|     def read_branches(self, chooser_button): | ||||
|         self.gitmidi = None | ||||
|         repo_path = chooser_button.get_file().get_path() | ||||
|         self.branch_combo.remove_all() | ||||
|         self.branch_combo.set_button_sensitivity(False) | ||||
|         self.set_buttons_sensitivity(disable_all=True) | ||||
|  | ||||
|         try: | ||||
|             repo = Repo(repo_path) | ||||
|         except InvalidGitRepositoryError: | ||||
|             dialog = self.Gtk.MessageDialog( | ||||
|                 chooser_button.get_toplevel(), | ||||
|                 self.Gtk.DialogFlags.MODAL, | ||||
|                 self.Gtk.MessageType.ERROR, | ||||
|                 self.Gtk.ButtonsType.OK, | ||||
|                 "{} is not a valid Git repository".format( | ||||
|                     repo_path)) | ||||
|  | ||||
|             dialog.connect('response', | ||||
|                            lambda dialog, response_id: dialog.destroy()) | ||||
|             dialog.run() | ||||
|  | ||||
|             return | ||||
|  | ||||
|         self.set_status('Opened repository: {}'.format(repo_path)) | ||||
|         self.branch_combo.set_button_sensitivity(True) | ||||
|  | ||||
|         for head in repo.heads: | ||||
|             self.branch_combo.append_text(head.name) | ||||
|  | ||||
|     def set_status(self, text): | ||||
|         self.statusbar.push(self.statusbar.get_context_id("git-sound"), text) | ||||
|  | ||||
|     def settings_changed(self, button): | ||||
|         self.gitmidi = None | ||||
|         self.set_buttons_sensitivity() | ||||
|         self.stop_midi() | ||||
|  | ||||
|     def set_buttons_sensitivity(self, disable_all=False): | ||||
|         generate_button = self.builder.get_object('generate-button') | ||||
|         stop_button = self.builder.get_object('stop-button') | ||||
|         save_button = self.builder.get_object('save-button') | ||||
|  | ||||
|         if disable_all: | ||||
|             generate_button.set_sensitive(False) | ||||
|             self.play_button.set_sensitive(False) | ||||
|             self.stop_button.set_sensitive(False) | ||||
|             save_button.set_sensitive(False) | ||||
|  | ||||
|             return | ||||
|  | ||||
|         if self.gitmidi is not None: | ||||
|             generate_button.set_sensitive(False) | ||||
|             self.play_button.set_sensitive(True) | ||||
|             self.stop_button.set_sensitive(False) | ||||
|             save_button.set_sensitive(True) | ||||
|  | ||||
|             return | ||||
|  | ||||
|         branch_selected = self.branch_combo.get_active_text() is not None | ||||
|         program_selected = self.program_combo.get_active_id() is not None | ||||
|         scale_selected = self.scale_combo.get_active_id() is not None | ||||
|  | ||||
|         if branch_selected and program_selected and scale_selected: | ||||
|             generate_button.set_sensitive(True) | ||||
|             self.play_button.set_sensitive(False) | ||||
|             self.stop_button.set_sensitive(False) | ||||
|             save_button.set_sensitive(False) | ||||
|  | ||||
|     def generate_repo(self, button): | ||||
|         chooser_button = self.builder.get_object('repo-chooser') | ||||
|         repo_path = chooser_button.get_file().get_path() | ||||
|         branch_selected = self.branch_combo.get_active_text() | ||||
|         program_selected = self.program_combo.get_active_id() | ||||
|         scale_selected = self.scale_combo.get_active_id() | ||||
|         skip = int(self.skip_spin.get_value()) | ||||
|         vol_deviation = int(self.vol_spin.get_value()) | ||||
|  | ||||
|         self.set_status("Generating data") | ||||
|         self.progressbar.set_fraction(0.0) | ||||
|         self.progressbar.pulse() | ||||
|         self.gitmidi = GitMIDI(repository=repo_path, | ||||
|                                branch=branch_selected, | ||||
|                                verbose=False, | ||||
|                                scale=scales[scale_selected][1], | ||||
|                                program=programs[program_selected], | ||||
|                                volume_range=vol_deviation, | ||||
|                                skip=skip) | ||||
|  | ||||
|         self.gitmidi.gen_repo_data(callback=self.genrepo_cb) | ||||
|         self.gitmidi.generate_midi(callback=self.genrepo_cb) | ||||
|         self.gitmidi.write_mem() | ||||
|  | ||||
|         self.set_buttons_sensitivity(disable_all=False) | ||||
|  | ||||
|     def genrepo_cb(self, max_count=None, current=None): | ||||
|         if max_count is None or current is None: | ||||
|             self.progressbar.pulse() | ||||
|         else: | ||||
|             self.progressbar.set_fraction(current / max_count) | ||||
|  | ||||
|         # Make sure the progress bar gets updated | ||||
|         self.Gtk.main_iteration_do(False) | ||||
|  | ||||
|     def update_play_pos(self): | ||||
|         position = self.gitmidi.get_play_pos() | ||||
|  | ||||
|         if position is None: | ||||
|             self.set_status("Stopped") | ||||
|             self.pos_label.set_text("0:00") | ||||
|             self.play_button.set_sensitive(True) | ||||
|             self.stop_button.set_sensitive(False) | ||||
|  | ||||
|             return False | ||||
|  | ||||
|         position = int(position / 1000) | ||||
|  | ||||
|         minutes = int(position / 60) | ||||
|         seconds = position - (minutes * 60) | ||||
|  | ||||
|         self.pos_label.set_text("{}:{:02}".format(minutes, seconds)) | ||||
|  | ||||
|         return True | ||||
|  | ||||
|     def play_midi(self): | ||||
|         self.set_status(u"Playing…") | ||||
|         self.gitmidi.play(track=True) | ||||
|         self.GLib.timeout_add_seconds(1, self.update_play_pos) | ||||
|         self.play_button.set_sensitive(False) | ||||
|         self.stop_button.set_sensitive(True) | ||||
|  | ||||
|     def stop_midi(self): | ||||
|         if self.gitmidi is not None: | ||||
|             self.gitmidi.stop() | ||||
|  | ||||
|     def start(self): | ||||
|         program_store = self.builder.get_object('program-list') | ||||
|         self.program_combo = self.builder.get_object('program-combo') | ||||
|  | ||||
|         for program_id, program in programs.items(): | ||||
|             program_store.append([program['name'], program_id]) | ||||
|  | ||||
|         renderer = self.Gtk.CellRendererText() | ||||
|         self.program_combo.pack_start(renderer, True) | ||||
|         self.program_combo.add_attribute(renderer, "text", 0) | ||||
|  | ||||
|         scale_store = self.builder.get_object('scale-list') | ||||
|         self.scale_combo = self.builder.get_object('scale-combo') | ||||
|  | ||||
|         for scale_id, scale in scales.items(): | ||||
|             scale_store.append([scale[0], scale_id]) | ||||
|  | ||||
|         renderer = self.Gtk.CellRendererText() | ||||
|         self.scale_combo.pack_start(renderer, True) | ||||
|         self.scale_combo.add_attribute(renderer, "text", 0) | ||||
|  | ||||
|         self.branch_combo = self.builder.get_object('branch-combo') | ||||
|         self.statusbar = self.builder.get_object('statusbar') | ||||
|         self.pos_label = self.builder.get_object('position-label') | ||||
|         self.skip_spin = self.builder.get_object('skip-spin') | ||||
|         self.vol_spin = self.builder.get_object('vol-spin') | ||||
|  | ||||
|         self.builder.connect_signals({ | ||||
|             'read_branches': lambda button: self.read_branches(button), | ||||
|             'settings_changed': lambda button: self.settings_changed(button), | ||||
|             'generate_repo': lambda button: self.generate_repo(button), | ||||
|             'play_midi': lambda button: self.play_midi(), | ||||
|             'stop_midi': lambda button: self.stop_midi(), | ||||
|         }) | ||||
|  | ||||
|         self.progressbar = self.builder.get_object('generate-progress') | ||||
|  | ||||
|         win = self.builder.get_object('main-window') | ||||
|         win.connect("delete-event", self.Gtk.main_quit) | ||||
|         win.show_all() | ||||
|         self.Gtk.main() | ||||
|  | ||||
|         sys.exit(0) | ||||
|  | ||||
|  | ||||
| def start_gui(): | ||||
|     win = GitSoundWindow() | ||||
|     win.start() | ||||
|  | ||||
|  | ||||
| class GitMIDI(MIDIFile): | ||||
|     LOG_CHANNEL = 0 | ||||
|     FILE_CHANNEL = 1 | ||||
| @@ -420,6 +622,9 @@ if __name__ == '__main__': | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     if args.scale is None and args.program is None: | ||||
|         start_gui() | ||||
|  | ||||
|     if args.scale is None and args.program != 'list': | ||||
|         print("Please specify a scale!") | ||||
|  | ||||
|   | ||||
							
								
								
									
										327
									
								
								git-sound.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								git-sound.ui
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,327 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- Generated with glade 3.16.1 --> | ||||
| <interface> | ||||
|   <requires lib="gtk+" version="3.10"/> | ||||
|   <object class="GtkImage" id="generate-image"> | ||||
|     <property name="visible">True</property> | ||||
|     <property name="sensitive">False</property> | ||||
|     <property name="can_focus">False</property> | ||||
|     <property name="icon_name">applications-system</property> | ||||
|   </object> | ||||
|   <object class="GtkListStore" id="program-list"> | ||||
|     <columns> | ||||
|       <!-- column-name program-name --> | ||||
|       <column type="gchararray"/> | ||||
|       <!-- column-name program-id --> | ||||
|       <column type="gchararray"/> | ||||
|     </columns> | ||||
|   </object> | ||||
|   <object class="GtkListStore" id="scale-list"> | ||||
|     <columns> | ||||
|       <!-- column-name program-name --> | ||||
|       <column type="gchararray"/> | ||||
|       <!-- column-name program-id --> | ||||
|       <column type="gchararray"/> | ||||
|     </columns> | ||||
|   </object> | ||||
|   <object class="GtkAdjustment" id="skip-adjustment"> | ||||
|     <property name="upper">100</property> | ||||
|     <property name="step_increment">1</property> | ||||
|     <property name="page_increment">10</property> | ||||
|   </object> | ||||
|   <object class="GtkAdjustment" id="vol-adjustment"> | ||||
|     <property name="upper">63</property> | ||||
|     <property name="value">10</property> | ||||
|     <property name="step_increment">1</property> | ||||
|     <property name="page_increment">10</property> | ||||
|   </object> | ||||
|   <object class="GtkWindow" id="main-window"> | ||||
|     <property name="can_focus">False</property> | ||||
|     <property name="title" translatable="yes">Git Sound</property> | ||||
|     <child> | ||||
|       <object class="GtkGrid" id="grid"> | ||||
|         <property name="visible">True</property> | ||||
|         <property name="can_focus">False</property> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="scale-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes" context="MIDI scale to use">Scale</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">1</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkComboBox" id="scale-combo"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="model">scale-list</property> | ||||
|             <property name="id_column">1</property> | ||||
|             <signal name="changed" handler="settings_changed" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">1</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="repo-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes" context="The repository to generate music for">Repository</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">2</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkFileChooserButton" id="repo-chooser"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="action">select-folder</property> | ||||
|             <signal name="file-set" handler="read_branches" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">2</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkButton" id="generate-button"> | ||||
|             <property name="label" translatable="yes">Generate</property> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="sensitive">False</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="receives_default">True</property> | ||||
|             <property name="image">generate-image</property> | ||||
|             <property name="always_show_image">True</property> | ||||
|             <signal name="clicked" handler="generate_repo" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">6</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkButton" id="play-button"> | ||||
|             <property name="label">gtk-media-play</property> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="sensitive">False</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="receives_default">True</property> | ||||
|             <property name="use_stock">True</property> | ||||
|             <property name="always_show_image">True</property> | ||||
|             <signal name="clicked" handler="play_midi" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">6</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkButton" id="save-button"> | ||||
|             <property name="label">gtk-save-as</property> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="sensitive">False</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="receives_default">True</property> | ||||
|             <property name="use_stock">True</property> | ||||
|             <property name="always_show_image">True</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">3</property> | ||||
|             <property name="top_attach">6</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkProgressBar" id="generate-progress"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="pulse_step">0.01</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">7</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="program-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes" context="The MIDI program to use">Program</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">0</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkComboBox" id="program-combo"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="model">program-list</property> | ||||
|             <property name="id_column">1</property> | ||||
|             <signal name="changed" handler="settings_changed" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">0</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="branch-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes">Branch</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">3</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkComboBoxText" id="branch-combo"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="button_sensitivity">off</property> | ||||
|             <signal name="changed" handler="settings_changed" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">3</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkStatusbar" id="statusbar"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="margin_left">10</property> | ||||
|             <property name="margin_right">10</property> | ||||
|             <property name="margin_top">6</property> | ||||
|             <property name="margin_bottom">6</property> | ||||
|             <property name="orientation">vertical</property> | ||||
|             <property name="spacing">2</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">8</property> | ||||
|             <property name="width">4</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="position-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label">0:00</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">3</property> | ||||
|             <property name="top_attach">7</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="skip-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes">Skip commits</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">4</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkSpinButton" id="skip-spin"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="text" translatable="yes">0</property> | ||||
|             <property name="adjustment">skip-adjustment</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">4</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkLabel" id="vol-label"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">False</property> | ||||
|             <property name="label" translatable="yes">Maximum volume deviation</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">0</property> | ||||
|             <property name="top_attach">5</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkSpinButton" id="vol-spin"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="text" translatable="yes">10</property> | ||||
|             <property name="adjustment">vol-adjustment</property> | ||||
|             <property name="value">10</property> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">1</property> | ||||
|             <property name="top_attach">5</property> | ||||
|             <property name="width">3</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child> | ||||
|           <object class="GtkButton" id="stop-button"> | ||||
|             <property name="label">gtk-media-stop</property> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="can_focus">True</property> | ||||
|             <property name="receives_default">True</property> | ||||
|             <property name="use_stock">True</property> | ||||
|             <property name="always_show_image">True</property> | ||||
|             <signal name="clicked" handler="stop_midi" swapped="no"/> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="left_attach">2</property> | ||||
|             <property name="top_attach">6</property> | ||||
|             <property name="width">1</property> | ||||
|             <property name="height">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|       </object> | ||||
|     </child> | ||||
|   </object> | ||||
| </interface> | ||||
		Reference in New Issue
	
	Block a user