Example #1
0
 def prepare_pipeline(self):
     gstsink = gst.parse_bin_from_description(self.sink, True)
     self.pipeline = Pipeline(gstsink)
     self.pipeline.reset()
     self.pipeline.set_file("file://" + self.filepath)
     self.pipeline.set_speed(self.speed)
     self.pipeline.set_on_eos_cb(self.on_eos)
Example #2
0
    def __init__(self, sink, config):
        Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(myGtk.iconfactory.get_icon("playitslowly", 128))
        except GObject.GError:
            print("could not load playitslowly icon")

        self.set_default_size(600, 200)
        self.set_border_width(5)

        self.vbox = Gtk.VBox()
        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = myGtk.FileChooserDialog(None, self, Gtk.FileChooserAction.OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = Gtk.HBox()
        self.filechooser = Gtk.FileChooserButton.new_with_dialog(self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True, 0)
        self.recentbutton = Gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False, 0)

        self.speedchooser = myGtk.TextScaleReset(Gtk.Adjustment.new(1.00, 0.10, 4.0, 0.05, 0.05, 0))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event", self.speedrelease)
        self.speedchangeing = False

        pitch_adjustment = Gtk.Adjustment.new(0.0, -24.0, 24.0, 1.0, 1.0, 1.0)
        self.pitchchooser = myGtk.TextScaleReset(pitch_adjustment)
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = myGtk.TextScaleReset(Gtk.Adjustment.new(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed", self.pitchchanged)

        self.positionchooser = myGtk.ClockScale(Gtk.Adjustment.new(0.0, 0.0, 100.0, 0, 0, 0))
        self.positionchooser.scale.connect("button-press-event", self.start_seeking)
        self.positionchooser.scale.connect("button-release-event", self.positionchanged)
        self.seeking = False

        self.startchooser = myGtk.TextScaleWithCurPos(self.positionchooser, Gtk.Adjustment.new(0.0, 0, 100.0, 0, 0, 0))
        self.startchooser.scale.connect("button-press-event", self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator(
            "clicked", self.accel_group, ord("["), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE
        )
        self.startchooser.add_accelerator("clicked", self.accel_group, ord("["), 0, Gtk.AccelFlags.VISIBLE)

        self.endchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser, Gtk.Adjustment.new(1.0, 0, 100.0, 0.01, 0.01, 0)
        )
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator(
            "clicked", self.accel_group, ord("]"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE
        )
        self.endchooser.add_accelerator("clicked", self.accel_group, ord("]"), 0, Gtk.AccelFlags.VISIBLE)

        self.vbox.pack_start(filechooserhbox, False, False, 0)
        self.vbox.pack_start(self.positionchooser, True, True, 0)
        self.vbox.pack_start(
            myGtk.form(
                [
                    (_("Speed (times)"), self.speedchooser),
                    (_("Pitch (semitones)"), self.pitchchooser),
                    (_("Fine Pitch (cents)"), self.pitchchooser_fine),
                    (_("Start Position (seconds)"), self.startchooser),
                    (_("End Position (seconds)"), self.endchooser),
                ]
            ),
            False,
            False,
            0,
        )

        buttonbox = Gtk.HButtonBox()
        myGtk.add_style_class(buttonbox, "buttonBox")
        self.vbox.pack_end(buttonbox, False, False, 0)

        self.play_button = Gtk.ToggleButton(stock=Gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button, True, True, 0)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(" "), 0, Gtk.AccelFlags.VISIBLE)

        self.back_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        # self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button, True, True, 0)

        self.volume_button = Gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button, True, True, 0)

        self.save_as_button = Gtk.Button.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button, True, True, 0)

        button_about = Gtk.Button.new_from_stock(Gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about, True, True, 0)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", Gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()
Example #3
0
class MainWindow(Gtk.Window):
    def __init__(self, sink, config):
        Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(myGtk.iconfactory.get_icon("playitslowly", 128))
        except GObject.GError:
            print("could not load playitslowly icon")

        self.set_default_size(600, 200)
        self.set_border_width(5)

        self.vbox = Gtk.VBox()
        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = myGtk.FileChooserDialog(None, self, Gtk.FileChooserAction.OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = Gtk.HBox()
        self.filechooser = Gtk.FileChooserButton.new_with_dialog(self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True, 0)
        self.recentbutton = Gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False, 0)

        self.speedchooser = myGtk.TextScaleReset(Gtk.Adjustment.new(1.00, 0.10, 4.0, 0.05, 0.05, 0))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event", self.speedrelease)
        self.speedchangeing = False

        pitch_adjustment = Gtk.Adjustment.new(0.0, -24.0, 24.0, 1.0, 1.0, 1.0)
        self.pitchchooser = myGtk.TextScaleReset(pitch_adjustment)
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = myGtk.TextScaleReset(Gtk.Adjustment.new(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed", self.pitchchanged)

        self.positionchooser = myGtk.ClockScale(Gtk.Adjustment.new(0.0, 0.0, 100.0, 0, 0, 0))
        self.positionchooser.scale.connect("button-press-event", self.start_seeking)
        self.positionchooser.scale.connect("button-release-event", self.positionchanged)
        self.seeking = False

        self.startchooser = myGtk.TextScaleWithCurPos(self.positionchooser, Gtk.Adjustment.new(0.0, 0, 100.0, 0, 0, 0))
        self.startchooser.scale.connect("button-press-event", self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator(
            "clicked", self.accel_group, ord("["), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE
        )
        self.startchooser.add_accelerator("clicked", self.accel_group, ord("["), 0, Gtk.AccelFlags.VISIBLE)

        self.endchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser, Gtk.Adjustment.new(1.0, 0, 100.0, 0.01, 0.01, 0)
        )
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator(
            "clicked", self.accel_group, ord("]"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE
        )
        self.endchooser.add_accelerator("clicked", self.accel_group, ord("]"), 0, Gtk.AccelFlags.VISIBLE)

        self.vbox.pack_start(filechooserhbox, False, False, 0)
        self.vbox.pack_start(self.positionchooser, True, True, 0)
        self.vbox.pack_start(
            myGtk.form(
                [
                    (_("Speed (times)"), self.speedchooser),
                    (_("Pitch (semitones)"), self.pitchchooser),
                    (_("Fine Pitch (cents)"), self.pitchchooser_fine),
                    (_("Start Position (seconds)"), self.startchooser),
                    (_("End Position (seconds)"), self.endchooser),
                ]
            ),
            False,
            False,
            0,
        )

        buttonbox = Gtk.HButtonBox()
        myGtk.add_style_class(buttonbox, "buttonBox")
        self.vbox.pack_end(buttonbox, False, False, 0)

        self.play_button = Gtk.ToggleButton(stock=Gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button, True, True, 0)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(" "), 0, Gtk.AccelFlags.VISIBLE)

        self.back_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        # self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button, True, True, 0)

        self.volume_button = Gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button, True, True, 0)

        self.save_as_button = Gtk.Button.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button, True, True, 0)

        button_about = Gtk.Button.new_from_stock(Gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about, True, True, 0)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", Gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()

    def speedpress(self, *args):
        self.speedchangeing = True

    def speedrelease(self, *args):
        self.speedchangeing = False
        self.speedchanged()

    def get_pitch(self):
        return self.pitchchooser.get_value() + self.pitchchooser_fine.get_value() * 0.01

    def set_pitch(self, value):
        semitones = round(value)
        cents = round((value - semitones) * 100)
        self.pitchchooser.set_value(semitones)
        self.pitchchooser_fine.set_value(cents)

    def add_recent(self, uri):
        manager = Gtk.RecentManager.get_default()
        app_exec = 'playitslowly "%s"' % uri
        mime_type, certain = Gio.content_type_guess(uri)
        if mime_type:
            recent_data = Gtk.RecentData()
            recent_data.app_name = "playitslowly"
            recent_data.app_exec = "playitslowly"
            recent_data.mime_type = mime_type
            manager.add_full(uri, recent_data)
            print(app_exec, mime_type)

    def show_recent(self, sender=None):
        dialog = Gtk.RecentChooserDialog(
            _("Recent Files"),
            self,
            None,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
        )

        filter = Gtk.RecentFilter()
        filter.set_name("playitslowly")
        filter.add_application("playitslowly")
        dialog.add_filter(filter)

        filter2 = Gtk.RecentFilter()
        filter2.set_name(_("All"))
        filter2.add_mime_type("audio/*")
        dialog.add_filter(filter2)

        dialog.set_local_only(False)

        dialog.set_filter(filter)

        if dialog.run() == Gtk.ResponseType.OK and dialog.get_current_item():
            uri = dialog.get_current_item().get_uri()
            if isinstance(uri, bytes):
                uri = uri.decode("utf-8")
            self.set_uri(uri)
        dialog.destroy()

    def set_uri(self, uri):
        print(repr(uri))
        self.filedialog.set_uri(uri)
        self.filechooser.set_uri(uri)
        self.filechanged(uri=uri)

    def load_config(self):
        self.config_saving = True  # do not save while loading
        lastfile = self.config.get("lastfile")
        if lastfile:
            self.set_uri(lastfile)
        self.config_saving = False

    def reset_settings(self):
        self.speedchooser.set_value(1.0)
        self.speedchanged()
        self.set_pitch(0.0)
        self.startchooser.get_adjustment().set_property("upper", 0.0)
        self.startchooser.set_value(0.0)
        self.endchooser.get_adjustment().set_property("upper", 1.0)
        self.endchooser.set_value(1.0)

    def load_file_settings(self, filename):
        print("load_file_settings", filename)
        self.add_recent(filename)
        if not self.config or not filename in self.config["files"]:
            self.reset_settings()
            self.pipeline.set_file(filename)
            self.pipeline.pause()
            GObject.timeout_add(100, self.update_position)
            return
        settings = self.config["files"][filename]
        self.speedchooser.set_value(settings["speed"])
        self.set_pitch(settings["pitch"])
        self.startchooser.get_adjustment().set_property("upper", settings["duration"])
        self.startchooser.set_value(settings["start"])
        self.endchooser.get_adjustment().set_property("upper", settings["duration"] or 1.0)
        self.endchooser.set_value(settings["end"])
        self.volume_button.set_value(settings["volume"])

    def save_config(self):
        """saves the config file with a delay"""
        if self.config_saving:
            return
        GObject.timeout_add(1000, self.save_config_now)
        self.config_saving = True

    def save_config_now(self):
        self.config_saving = False
        lastfile = self.filedialog.get_uri()
        self.config["lastfile"] = lastfile
        settings = {}
        settings["speed"] = self.speedchooser.get_value()
        settings["pitch"] = self.get_pitch()
        settings["duration"] = self.startchooser.get_adjustment().get_property("upper")
        settings["start"] = self.startchooser.get_value()
        settings["end"] = self.endchooser.get_value()
        settings["volume"] = self.volume_button.get_value()
        self.config.setdefault("files", {})[lastfile] = settings

        self.config.save()

    def key_release(self, sender, event):
        if not event.get_state() & Gdk.ModifierType.CONTROL_MASK:
            return
        try:
            val = int(chr(event.keyval))
        except ValueError:
            return
        self.back(self, val)

    def volumechanged(self, sender, foo):
        self.pipeline.set_volume(sender.get_value())
        self.save_config()

    def save(self, sender):
        dialog = myGtk.FileChooserDialog(_("Save modified version as"), self, Gtk.FileChooserAction.SAVE)
        dialog.set_current_name("export.wav")
        if dialog.run() == Gtk.ResponseType.OK:
            self.pipeline.set_file(self.filedialog.get_uri())
            self.foo = self.pipeline.save_file(dialog.get_filename())
        dialog.destroy()

    def filechanged(self, sender=None, response_id=Gtk.ResponseType.OK, uri=None):
        print("file changed", uri)
        if response_id != Gtk.ResponseType.OK:
            return

        self.play_button.set_sensitive(True)
        self.back_button.set_sensitive(True)
        self.save_as_button.set_sensitive(True)
        self.play_button.set_active(False)

        self.pipeline.reset()
        self.seek(0)
        self.save_config()

        if uri:
            self.load_file_settings(uri)
        else:
            # for what ever reason filedialog.get_uri() is sometimes None until the
            # mainloop ran through
            GObject.timeout_add(1, lambda: self.load_file_settings(self.filedialog.get_uri()))

    def start_seeking(self, sender, foo):
        self.seeking = True

    def seeked(self, sender, foo):
        self.seeking = False
        self.save_config()

    def positionchanged(self, sender, foo):
        self.seek(sender.get_value())
        self.seeking = False
        self.save_config()

    def seek(self, pos=0):
        if self.positionchooser.get_value() != pos:
            self.positionchooser.set_value(pos)
        pos = self.pipeline.pipe_time(pos)
        self.pipeline.playbin.seek_simple(TIME_FORMAT, Gst.SeekFlags.FLUSH, pos or 0)

    def speedchanged(self, *args):
        if self.speedchangeing:
            return
        pos = self.positionchooser.get_value()
        self.pipeline.set_speed(self.speedchooser.get_value())
        # hack to get gstreamer to calculate the position again
        self.seek(pos)
        self.save_config()

    def pitchchanged(self, sender):
        self.pipeline.set_pitch(2 ** (self.get_pitch() / 12.0))
        self.save_config()

    def back(self, sender, amount=None):
        position, fmt = self.pipeline.playbin.query_position(TIME_FORMAT)
        if position is None:
            return
        if amount:
            t = self.pipeline.song_time(position) - amount
            if t < 0:
                t = 0
        else:
            t = self.startchooser.get_value()
        self.seek(t)

    def play(self, sender):
        if sender.get_active():
            self.pipeline.set_file(self.filedialog.get_uri())
            self.pipeline.play()
            GObject.timeout_add(100, self.update_position)
        else:
            self.pipeline.pause()

    def update_position(self):
        """update the position of the scales and pipeline"""
        if self.seeking:
            return self.play_button.get_active()

        _, position = self.pipeline.playbin.query_position(TIME_FORMAT)
        _, duration = self.pipeline.playbin.query_duration(TIME_FORMAT)
        if position is None or duration is None:
            return self.play_button.get_active()
        position = position
        duration = duration
        position = self.pipeline.song_time(position)
        duration = self.pipeline.song_time(duration)

        if self.positionchooser.get_adjustment().get_property("upper") != duration:
            self.positionchooser.set_range(0.0, duration)
            self.save_config()

        end_adjustment = self.endchooser.get_adjustment()
        delta = end_adjustment.get_value() - end_adjustment.get_upper()

        if delta <= -duration:
            delta = 0

        self.startchooser.set_range(0.0, duration)
        self.endchooser.set_range(0.0, duration)
        self.endchooser.set_value(duration + delta)

        self.positionchooser.set_value(position)
        self.positionchooser.queue_draw()

        start = self.startchooser.get_value()
        end = self.endchooser.get_value()

        if end <= start:
            self.play_button.set_active(False)
            return False

        if position >= end or position < start:
            self.seek(start + 0.01)
            return True

        return self.play_button.get_active()

    def about(self, sender):
        """show an about dialog"""
        about = Gtk.AboutDialog()
        about.set_transient_for(self)
        about.set_logo(myGtk.iconfactory.get_icon("playitslowly", 128))
        about.set_name(NAME)
        about.set_program_name(NAME)
        about.set_version(VERSION)
        about.set_authors(["Jonas Wagner", "Elias Dorneles"])
        about.set_translator_credits(_("translator-credits"))
        about.set_copyright("Copyright (c) 2009 - 2015 Jonas Wagner")
        about.set_website(WEBSITE)
        about.set_website_label(WEBSITE)
        about.set_license(
            """
Copyright (C) 2009 - 2015 Jonas Wagner
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
"""
        )
        about.run()
        about.destroy()
Example #4
0
    def __init__(self, sink, config):
        gtk.Window.__init__(self,gtk.WINDOW_TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(mygtk.iconfactory.get_icon("playitslowly", 128))
        except gobject.GError:
            print "could not load playitslowly icon"

        self.set_default_size(500, 200)
        self.set_border_width(5)

        self.vbox = gtk.VBox()
        self.accel_group = gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = mygtk.FileChooserDialog(None, self, gtk.FILE_CHOOSER_ACTION_OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = gtk.HBox()
        self.filechooser = gtk.FileChooserButton(self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True)
        self.recentbutton = gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False)

        self.speedchooser = mygtk.TextScaleReset(gtk.Adjustment(1.00, 0.10, 4.0, 0.05, 0.05))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event", self.speedrelease)
        self.speedchangeing = False

        self.pitchchooser = mygtk.TextScaleReset(gtk.Adjustment(0.0, -24.0, 24.0, 1.0, 1.0, 1.0))
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = mygtk.TextScaleReset(gtk.Adjustment(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed", self.pitchchanged)

        self.positionchooser = mygtk.ClockScale(gtk.Adjustment(0.0, 0.0, 100.0))
        self.positionchooser.scale.connect("button-press-event", self.start_seeking)
        self.positionchooser.scale.connect("button-release-event", self.positionchanged)
        self.seeking = False

        self.startchooser = mygtk.TextScaleWithCurPos(self.positionchooser, gtk.Adjustment(0.0, 0, 100.0))
        self.startchooser.scale.connect("button-press-event", self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator("clicked", self.accel_group, ord('['), gtk.gdk.CONTROL_MASK, ())
        self.startchooser.add_accelerator("clicked", self.accel_group, ord('['), 0, ())

        self.endchooser = mygtk.TextScaleWithCurPos(self.positionchooser, gtk.Adjustment(1.0, 0, 100.0, 0.01, 0.01))
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'), gtk.gdk.CONTROL_MASK, ())
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'), 0, ())

        self.vbox.pack_start(filechooserhbox)
        self.vbox.pack_start(self.positionchooser)
        self.vbox.pack_start(mygtk.form([(_(u"Speed (times)"), self.speedchooser),
            (_(u"Pitch (semitones)"), self.pitchchooser),
            (_(u"Fine Pitch (cents)"), self.pitchchooser_fine),
            (_(u"Start Position (seconds)"), self.startchooser),
            (_(u"End Position (seconds)"), self.endchooser)
        ]), False, False)

        buttonbox = gtk.HButtonBox()
        self.vbox.pack_end(buttonbox, False, False)

        self.play_button = gtk.ToggleButton(gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button)
        # make SPACE a shortcut for play/pause (CTRL-SPC would be better?)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(' '), 0, ())

        self.back_button = gtk.Button(gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button)

        self.volume_button = gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(gtk.RELIEF_NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button)

        self.save_as_button = gtk.Button(stock=gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button)

        button_about = gtk.Button(stock=gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()
Example #5
0
    def __init__(self, sink, config):
        Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(
                myGtk.iconfactory.get_icon("ch.x29a.playitslowly", 128))
        except GObject.GError:
            print("could not load playitslowly icon")

        self.set_default_size(600, 200)
        self.set_border_width(5)

        self.vbox = Gtk.VBox()
        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = myGtk.FileChooserDialog(None, self,
                                                  Gtk.FileChooserAction.OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = Gtk.HBox()
        self.filechooser = Gtk.FileChooserButton.new_with_dialog(
            self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True, 0)
        self.recentbutton = Gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False, 0)

        self.speedchooser = myGtk.TextScaleReset(
            Gtk.Adjustment.new(1.00, 0.10, 4.0, 0.05, 0.05, 0))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event",
                                        self.speedrelease)
        self.speedchangeing = False

        pitch_adjustment = Gtk.Adjustment.new(0.0, -24.0, 24.0, 1.0, 1.0, 1.0)
        self.pitchchooser = myGtk.TextScaleReset(pitch_adjustment)
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = myGtk.TextScaleReset(
            Gtk.Adjustment.new(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed",
                                             self.pitchchanged)

        self.positionchooser = myGtk.ClockScale(
            Gtk.Adjustment.new(0.0, 0.0, 100.0, 0, 0, 0))
        self.positionchooser.scale.connect("button-press-event",
                                           self.start_seeking)
        self.positionchooser.scale.connect("button-release-event",
                                           self.positionchanged)
        self.seeking = False

        self.startchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser, Gtk.Adjustment.new(0.0, 0, 100.0, 0, 0, 0))
        self.startchooser.scale.connect("button-press-event",
                                        self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['),
                                          Gdk.ModifierType.CONTROL_MASK,
                                          Gtk.AccelFlags.VISIBLE)
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['), 0, Gtk.AccelFlags.VISIBLE)

        self.endchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser,
            Gtk.Adjustment.new(1.0, 0, 100.0, 0.01, 0.01, 0))
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        Gdk.ModifierType.CONTROL_MASK,
                                        Gtk.AccelFlags.VISIBLE)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        0, Gtk.AccelFlags.VISIBLE)

        self.vbox.pack_start(filechooserhbox, False, False, 0)
        self.vbox.pack_start(self.positionchooser, True, True, 0)
        self.vbox.pack_start(
            myGtk.form([(_("Speed (times)"), self.speedchooser),
                        (_("Pitch (semitones)"), self.pitchchooser),
                        (_("Fine Pitch (cents)"), self.pitchchooser_fine),
                        (_("Start Position (seconds)"), self.startchooser),
                        (_("End Position (seconds)"), self.endchooser)]),
            False, False, 0)

        buttonbox = Gtk.HButtonBox()
        myGtk.add_style_class(buttonbox, 'buttonBox')
        self.vbox.pack_end(buttonbox, False, False, 0)

        self.play_button = Gtk.ToggleButton(stock=Gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button, True, True, 0)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(' '),
                                         0, Gtk.AccelFlags.VISIBLE)

        self.back_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        #self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button, True, True, 0)

        self.volume_button = Gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button, True, True, 0)

        self.save_as_button = Gtk.Button.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button, True, True, 0)

        button_about = Gtk.Button.new_from_stock(Gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about, True, True, 0)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", Gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()
Example #6
0
class MainWindow(Gtk.Window):
    def __init__(self, sink, config):
        Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(
                myGtk.iconfactory.get_icon("ch.x29a.playitslowly", 128))
        except GObject.GError:
            print("could not load playitslowly icon")

        self.set_default_size(600, 200)
        self.set_border_width(5)

        self.vbox = Gtk.VBox()
        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = myGtk.FileChooserDialog(None, self,
                                                  Gtk.FileChooserAction.OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = Gtk.HBox()
        self.filechooser = Gtk.FileChooserButton.new_with_dialog(
            self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True, 0)
        self.recentbutton = Gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False, 0)

        self.speedchooser = myGtk.TextScaleReset(
            Gtk.Adjustment.new(1.00, 0.10, 4.0, 0.05, 0.05, 0))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event",
                                        self.speedrelease)
        self.speedchangeing = False

        pitch_adjustment = Gtk.Adjustment.new(0.0, -24.0, 24.0, 1.0, 1.0, 1.0)
        self.pitchchooser = myGtk.TextScaleReset(pitch_adjustment)
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = myGtk.TextScaleReset(
            Gtk.Adjustment.new(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed",
                                             self.pitchchanged)

        self.positionchooser = myGtk.ClockScale(
            Gtk.Adjustment.new(0.0, 0.0, 100.0, 0, 0, 0))
        self.positionchooser.scale.connect("button-press-event",
                                           self.start_seeking)
        self.positionchooser.scale.connect("button-release-event",
                                           self.positionchanged)
        self.seeking = False

        self.startchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser, Gtk.Adjustment.new(0.0, 0, 100.0, 0, 0, 0))
        self.startchooser.scale.connect("button-press-event",
                                        self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['),
                                          Gdk.ModifierType.CONTROL_MASK,
                                          Gtk.AccelFlags.VISIBLE)
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['), 0, Gtk.AccelFlags.VISIBLE)

        self.endchooser = myGtk.TextScaleWithCurPos(
            self.positionchooser,
            Gtk.Adjustment.new(1.0, 0, 100.0, 0.01, 0.01, 0))
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        Gdk.ModifierType.CONTROL_MASK,
                                        Gtk.AccelFlags.VISIBLE)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        0, Gtk.AccelFlags.VISIBLE)

        self.vbox.pack_start(filechooserhbox, False, False, 0)
        self.vbox.pack_start(self.positionchooser, True, True, 0)
        self.vbox.pack_start(
            myGtk.form([(_("Speed (times)"), self.speedchooser),
                        (_("Pitch (semitones)"), self.pitchchooser),
                        (_("Fine Pitch (cents)"), self.pitchchooser_fine),
                        (_("Start Position (seconds)"), self.startchooser),
                        (_("End Position (seconds)"), self.endchooser)]),
            False, False, 0)

        buttonbox = Gtk.HButtonBox()
        myGtk.add_style_class(buttonbox, 'buttonBox')
        self.vbox.pack_end(buttonbox, False, False, 0)

        self.play_button = Gtk.ToggleButton(stock=Gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button, True, True, 0)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(' '),
                                         0, Gtk.AccelFlags.VISIBLE)

        self.back_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        #self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button, True, True, 0)

        self.volume_button = Gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(Gtk.ReliefStyle.NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button, True, True, 0)

        self.save_as_button = Gtk.Button.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button, True, True, 0)

        button_about = Gtk.Button.new_from_stock(Gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about, True, True, 0)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", Gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()

    def speedpress(self, *args):
        self.speedchangeing = True

    def speedrelease(self, *args):
        self.speedchangeing = False
        self.speedchanged()

    def get_pitch(self):
        return self.pitchchooser.get_value(
        ) + self.pitchchooser_fine.get_value() * 0.01

    def set_pitch(self, value):
        semitones = round(value)
        cents = round((value - semitones) * 100)
        self.pitchchooser.set_value(semitones)
        self.pitchchooser_fine.set_value(cents)

    def add_recent(self, uri):
        manager = Gtk.RecentManager.get_default()
        app_exec = "playitslowly \"%s\"" % uri
        mime_type, certain = Gio.content_type_guess(uri)
        if mime_type:
            recent_data = Gtk.RecentData()
            recent_data.app_name = "playitslowly"
            recent_data.app_exec = "playitslowly"
            recent_data.mime_type = mime_type
            manager.add_full(uri, recent_data)
            print(app_exec, mime_type)

    def show_recent(self, sender=None):
        dialog = Gtk.RecentChooserDialog(
            _("Recent Files"), self, None,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.RecentFilter()
        filter.set_name("playitslowly")
        filter.add_application("playitslowly")
        dialog.add_filter(filter)

        filter2 = Gtk.RecentFilter()
        filter2.set_name(_("All"))
        filter2.add_mime_type("audio/*")
        dialog.add_filter(filter2)

        dialog.set_local_only(False)

        dialog.set_filter(filter)

        if dialog.run() == Gtk.ResponseType.OK and dialog.get_current_item():
            uri = dialog.get_current_item().get_uri()
            if isinstance(uri, bytes):
                uri = uri.decode('utf-8')
            self.set_uri(uri)
        dialog.destroy()

    def set_uri(self, uri):
        print(repr(uri))
        self.filedialog.set_uri(uri)
        self.filechooser.set_uri(uri)
        self.filechanged(uri=uri)

    def load_config(self):
        self.config_saving = True  # do not save while loading
        lastfile = self.config.get("lastfile")
        if lastfile:
            self.set_uri(lastfile)
        self.config_saving = False

    def reset_settings(self):
        self.speedchooser.set_value(1.0)
        self.speedchanged()
        self.set_pitch(0.0)
        self.startchooser.get_adjustment().set_property("upper", 0.0)
        self.startchooser.set_value(0.0)
        self.endchooser.get_adjustment().set_property("upper", 1.0)
        self.endchooser.set_value(1.0)

    def load_file_settings(self, filename):
        print("load_file_settings", filename)
        self.add_recent(filename)
        if not self.config or not filename in self.config["files"]:
            self.reset_settings()
            self.pipeline.set_file(filename)
            self.pipeline.pause()
            GObject.timeout_add(100, self.update_position)
            return
        settings = self.config["files"][filename]
        self.speedchooser.set_value(settings["speed"])
        self.set_pitch(settings["pitch"])
        self.startchooser.get_adjustment().set_property(
            "upper", settings["duration"])
        self.startchooser.set_value(settings["start"])
        self.endchooser.get_adjustment().set_property(
            "upper", settings["duration"] or 1.0)
        self.endchooser.set_value(settings["end"])
        self.volume_button.set_value(settings["volume"])

    def save_config(self):
        """saves the config file with a delay"""
        if self.config_saving:
            return
        GObject.timeout_add(1000, self.save_config_now)
        self.config_saving = True

    def save_config_now(self):
        self.config_saving = False
        lastfile = self.filedialog.get_uri()
        self.config["lastfile"] = lastfile
        settings = {}
        settings["speed"] = self.speedchooser.get_value()
        settings["pitch"] = self.get_pitch()
        settings["duration"] = self.startchooser.get_adjustment().get_property(
            "upper")
        settings["start"] = self.startchooser.get_value()
        settings["end"] = self.endchooser.get_value()
        settings["volume"] = self.volume_button.get_value()
        self.config.setdefault("files", {})[lastfile] = settings

        self.config.save()

    def key_release(self, sender, event):
        if not event.get_state() & Gdk.ModifierType.CONTROL_MASK:
            return
        try:
            val = int(chr(event.keyval))
        except ValueError:
            return
        self.back(self, val)

    def volumechanged(self, sender, foo):
        self.pipeline.set_volume(sender.get_value())
        self.save_config()

    def save(self, sender):
        dialog = myGtk.FileChooserDialog(_("Save modified version as"), self,
                                         Gtk.FileChooserAction.SAVE)
        dialog.set_current_name("export.wav")
        if dialog.run() == Gtk.ResponseType.OK:
            self.pipeline.set_file(self.filedialog.get_uri())
            self.foo = self.pipeline.save_file(dialog.get_filename())
        dialog.destroy()

    def filechanged(self,
                    sender=None,
                    response_id=Gtk.ResponseType.OK,
                    uri=None):
        print("file changed", uri)
        if response_id != Gtk.ResponseType.OK:
            return

        self.play_button.set_sensitive(True)
        self.back_button.set_sensitive(True)
        self.save_as_button.set_sensitive(True)
        self.play_button.set_active(False)

        self.pipeline.reset()
        self.seek(0)
        self.save_config()

        if uri:
            self.load_file_settings(uri)
        else:
            # for what ever reason filedialog.get_uri() is sometimes None until the
            # mainloop ran through
            GObject.timeout_add(
                1, lambda: self.load_file_settings(self.filedialog.get_uri()))

    def start_seeking(self, sender, foo):
        self.seeking = True

    def seeked(self, sender, foo):
        self.seeking = False
        self.save_config()

    def positionchanged(self, sender, foo):
        self.seek(sender.get_value())
        self.seeking = False
        self.save_config()

    def seek(self, pos=0):
        if self.positionchooser.get_value() != pos:
            self.positionchooser.set_value(pos)
        pos = self.pipeline.pipe_time(pos)
        self.pipeline.playbin.seek_simple(TIME_FORMAT, Gst.SeekFlags.FLUSH, pos
                                          or 0)

    def speedchanged(self, *args):
        if self.speedchangeing:
            return
        pos = self.positionchooser.get_value()
        self.pipeline.set_speed(self.speedchooser.get_value())
        # hack to get gstreamer to calculate the position again
        self.seek(pos)
        self.save_config()

    def pitchchanged(self, sender):
        self.pipeline.set_pitch(2**(self.get_pitch() / 12.0))
        self.save_config()

    def back(self, sender, amount=None):
        position, fmt = self.pipeline.playbin.query_position(TIME_FORMAT)
        if position is None:
            return
        if amount:
            t = self.pipeline.song_time(position) - amount
            if t < 0:
                t = 0
        else:
            t = self.startchooser.get_value()
        self.seek(t)

    def play(self, sender):
        if sender.get_active():
            self.pipeline.set_file(self.filedialog.get_uri())
            self.pipeline.play()
            GObject.timeout_add(100, self.update_position)
        else:
            self.pipeline.pause()

    def update_position(self):
        """update the position of the scales and pipeline"""
        if self.seeking:
            return self.play_button.get_active()

        _, position = self.pipeline.playbin.query_position(TIME_FORMAT)
        _, duration = self.pipeline.playbin.query_duration(TIME_FORMAT)
        if position is None or duration is None:
            return self.play_button.get_active()
        position = position
        duration = duration
        position = self.pipeline.song_time(position)
        duration = self.pipeline.song_time(duration)

        if self.positionchooser.get_adjustment().get_property(
                "upper") != duration:
            self.positionchooser.set_range(0.0, duration)
            self.save_config()

        end_adjustment = self.endchooser.get_adjustment()
        delta = end_adjustment.get_value() - end_adjustment.get_upper()

        if delta <= -duration:
            delta = 0

        self.startchooser.set_range(0.0, duration)
        self.endchooser.set_range(0.0, duration)
        self.endchooser.set_value(duration + delta)

        self.positionchooser.set_value(position)
        self.positionchooser.queue_draw()

        start = self.startchooser.get_value()
        end = self.endchooser.get_value()

        if end <= start:
            self.play_button.set_active(False)
            return False

        if position >= end or position < start:
            self.seek(start + 0.01)
            return True

        return self.play_button.get_active()

    def about(self, sender):
        """show an about dialog"""
        about = Gtk.AboutDialog()
        about.set_transient_for(self)
        about.set_logo(myGtk.iconfactory.get_icon("ch.x29a.playitslowly", 128))
        about.set_name(NAME)
        about.set_program_name(NAME)
        about.set_version(VERSION)
        about.set_authors(["Jonas Wagner", "Elias Dorneles"])
        about.set_translator_credits(_("translator-credits"))
        about.set_copyright("Copyright (c) 2009 - 2015 Jonas Wagner")
        about.set_website(WEBSITE)
        about.set_website_label(WEBSITE)
        about.set_license("""
Copyright (C) 2009 - 2015 Jonas Wagner
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
""")
        about.run()
        about.destroy()
Example #7
0
class MainWindow(gtk.Window):
    def __init__(self, sink, config):
        gtk.Window.__init__(self,gtk.WINDOW_TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(mygtk.iconfactory.get_icon("playitslowly", 128))
        except gobject.GError:
            print "could not load playitslowly icon"

        self.set_default_size(500, 200)
        self.set_border_width(5)

        self.vbox = gtk.VBox()
        self.accel_group = gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = mygtk.FileChooserDialog(None, self, gtk.FILE_CHOOSER_ACTION_OPEN)
        self.filedialog.connect("response", self.filechanged)
        filechooserhbox = gtk.HBox()
        self.filechooser = gtk.FileChooserButton(self.filedialog)
        filechooserhbox.pack_start(self.filechooser, True, True)
        self.recentbutton = gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False)

        self.speedchooser = mygtk.TextScaleReset(gtk.Adjustment(1.00, 0.10, 4.0, 0.05, 0.05))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event", self.speedrelease)
        self.speedchangeing = False

        self.pitchchooser = mygtk.TextScaleReset(gtk.Adjustment(0.0, -24.0, 24.0, 1.0, 1.0, 1.0))
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = mygtk.TextScaleReset(gtk.Adjustment(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed", self.pitchchanged)

        self.positionchooser = mygtk.ClockScale(gtk.Adjustment(0.0, 0.0, 100.0))
        self.positionchooser.scale.connect("button-press-event", self.start_seeking)
        self.positionchooser.scale.connect("button-release-event", self.positionchanged)
        self.seeking = False

        self.startchooser = mygtk.TextScaleWithCurPos(self.positionchooser, gtk.Adjustment(0.0, 0, 100.0))
        self.startchooser.scale.connect("button-press-event", self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator("clicked", self.accel_group, ord('['), gtk.gdk.CONTROL_MASK, ())
        self.startchooser.add_accelerator("clicked", self.accel_group, ord('['), 0, ())

        self.endchooser = mygtk.TextScaleWithCurPos(self.positionchooser, gtk.Adjustment(1.0, 0, 100.0, 0.01, 0.01))
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'), gtk.gdk.CONTROL_MASK, ())
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'), 0, ())

        self.vbox.pack_start(filechooserhbox)
        self.vbox.pack_start(self.positionchooser)
        self.vbox.pack_start(mygtk.form([(_(u"Speed (times)"), self.speedchooser),
            (_(u"Pitch (semitones)"), self.pitchchooser),
            (_(u"Fine Pitch (cents)"), self.pitchchooser_fine),
            (_(u"Start Position (seconds)"), self.startchooser),
            (_(u"End Position (seconds)"), self.endchooser)
        ]), False, False)

        buttonbox = gtk.HButtonBox()
        self.vbox.pack_end(buttonbox, False, False)

        self.play_button = gtk.ToggleButton(gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button)
        # make SPACE a shortcut for play/pause (CTRL-SPC would be better?)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(' '), 0, ())

        self.back_button = gtk.Button(gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button)

        self.volume_button = gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(gtk.RELIEF_NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button)

        self.save_as_button = gtk.Button(stock=gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button)

        button_about = gtk.Button(stock=gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()

    def speedpress(self, *args):
        self.speedchangeing = True

    def speedrelease(self, *args):
        self.speedchangeing = False
        self.speedchanged()

    def get_pitch(self):
        return self.pitchchooser.get_value()+self.pitchchooser_fine.get_value()*0.01

    def set_pitch(self, value):
        semitones = round(value)
        cents = round((value-semitones)*100)
        self.pitchchooser.set_value(semitones)
        self.pitchchooser_fine.set_value(cents)

    def add_recent(self, uri):
        manager = gtk.recent_manager_get_default()
        app_exec = "playitslowly \"%s\"" % uri
        mime_type = mimetypes.guess_type(uri)[0]
        if mime_type:
            manager.add_full(uri, {
                "app_name": "playitslowly",
                "app_exec": "playitslowly",
                "mime_type": mime_type
            })


    def show_recent(self, sender=None):
        dialog = gtk.RecentChooserDialog(_("Recent Files"), self, None,
                (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                 gtk.STOCK_OPEN, gtk.RESPONSE_OK))

        filter = gtk.RecentFilter()
        filter.set_name("playitslowly")
        filter.add_application("playitslowly")
        dialog.add_filter(filter)

        filter2 = gtk.RecentFilter()
        filter2.set_name(_("All"))
        filter2.add_mime_type("audio/*")
        dialog.add_filter(filter2)

        dialog.set_filter(filter)

        if dialog.run() == gtk.RESPONSE_OK and dialog.get_current_item():
            uri = dialog.get_current_item().get_uri()
            self.filedialog.set_uri(dialog.get_current_item().get_uri())
            self.filechanged(uri=uri)
        dialog.destroy()

    def load_config(self):
        self.config_saving = True # do not save while loading
        lastfile = self.config.get("lastfile")
        if lastfile:
            self.filedialog.set_uri(lastfile)
            self.filechanged(uri=lastfile)
        self.config_saving = False

    def reset_settings(self):
        self.speedchooser.set_value(1.0)
        self.speedchanged()
        self.set_pitch(0.0)
        self.startchooser.get_adjustment().set_property("upper", 0.0)
        self.startchooser.set_value(0.0)
        self.endchooser.get_adjustment().set_property("upper", 1.0)
        self.endchooser.set_value(1.0)

    def load_file_settings(self, filename):
        self.add_recent(filename)
        if not self.config or not filename in self.config["files"]:
            self.reset_settings()
            self.pipeline.set_file(self.filedialog.get_uri())
            self.pipeline.pause()
            gobject.timeout_add(100, self.update_position)
            return
        settings = self.config["files"][filename]
        self.speedchooser.set_value(settings["speed"])
        self.set_pitch(settings["pitch"])
        self.startchooser.get_adjustment().set_property("upper", settings["duration"])
        self.startchooser.set_value(settings["start"])
        self.endchooser.get_adjustment().set_property("upper", settings["duration"] or 1.0)
        self.endchooser.set_value(settings["end"])
        self.volume_button.set_value(settings["volume"])

    def save_config(self):
        """saves the config file with a delay"""
        if self.config_saving:
            return
        gobject.timeout_add(1000, self.save_config_now)
        self.config_saving = True

    def save_config_now(self):
        self.config_saving = False
        lastfile = self.filedialog.get_uri()
        self.config["lastfile"] = lastfile
        settings = {}
        settings["speed"] = self.speedchooser.get_value()
        settings["pitch"] = self.get_pitch()
        settings["duration"] = self.startchooser.get_adjustment().get_property("upper")
        settings["start"] = self.startchooser.get_value()
        settings["end"] = self.endchooser.get_value()
        settings["volume"] = self.volume_button.get_value()
        self.config.setdefault("files", {})[lastfile] = settings

        self.config.save()

    def key_release(self, sender, event):
        if not event.state & gtk.gdk.CONTROL_MASK:
            return
        try:
            val = int(chr(event.keyval))
        except ValueError:
            return
        self.back(self, val)

    def volumechanged(self, sender, foo):
        self.pipeline.set_volume(sender.get_value())
        self.save_config()

    def save(self, sender):
        dialog = mygtk.FileChooserDialog(_(u"Save modified version as"),
                self, gtk.FILE_CHOOSER_ACTION_SAVE)
        dialog.set_current_name("export.wav")
        if dialog.run() == gtk.RESPONSE_OK:
            self.pipeline.set_file(self.filedialog.get_uri())
            self.foo = self.pipeline.save_file(dialog.get_filename())
        dialog.destroy()

    def filechanged(self, sender=None, response_id=gtk.RESPONSE_OK, uri=None):
        if response_id != gtk.RESPONSE_OK:
            return

        self.play_button.set_sensitive(True)
        self.back_button.set_sensitive(True)
        self.save_as_button.set_sensitive(True)
        self.play_button.set_active(False)

        self.pipeline.reset()
        self.seek(0)
        self.save_config()

        if uri:
            self.load_file_settings(uri)
        else:
            # for what ever reason filedialog.get_uri() is sometimes None until the
            # mainloop ran through
            gobject.timeout_add(1, lambda: self.load_file_settings(self.filedialog.get_uri()))

    def start_seeking(self, sender, foo):
        self.seeking = True

    def seeked(self, sender, foo):
        self.seeking = False
        self.save_config()

    def positionchanged(self, sender, foo):
        self.seek(sender.get_value())
        self.seeking = False
        self.save_config()

    def seek(self, pos):
        if self.positionchooser.get_value() != pos:
            self.positionchooser.set_value(pos)
        pos = self.pipeline.pipe_time(pos)
        self.pipeline.playbin.seek_simple(TIME_FORMAT, gst.SEEK_FLAG_FLUSH, pos)

    def speedchanged(self, *args):
        if self.speedchangeing:
            return
        pos = self.positionchooser.get_value()
        self.pipeline.set_speed(self.speedchooser.get_value())
        # hack to get gstreamer to calculate the position again
        self.seek(pos)
        self.save_config()

    def pitchchanged(self, sender):
        self.pipeline.set_pitch(2**(self.get_pitch()/12.0))
        self.save_config()

    def back(self, sender, amount=None):
        try:
            position, fmt = self.pipeline.playbin.query_position(TIME_FORMAT, None)
        except gst.QueryError:
            return
        if amount:
            t = self.pipeline.song_time(position)-amount
            if t < 0:
                t = 0
        else:
            t = 0
        self.seek(t)

    def play(self, sender):
        if sender.get_active():
            self.pipeline.set_file(self.filedialog.get_uri())
            self.pipeline.play()
            gobject.timeout_add(100, self.update_position)
        else:
            self.pipeline.pause()

    def update_position(self):
        """update the position of the scales and pipeline"""
        if self.seeking:
            return self.play_button.get_active()
        try:
            position, fmt = self.pipeline.playbin.query_position(TIME_FORMAT, None)
            duration, fmt = self.pipeline.playbin.query_duration(TIME_FORMAT, None)
        except gst.QueryError:
            return self.play_button.get_active()
        position = self.pipeline.song_time(position)
        duration = self.pipeline.song_time(duration)
        start = self.startchooser.get_value()
        end = self.endchooser.get_value()

        if end <= start:
            self.play_button.set_active(False)
            return False

        if position >= end or position < start:
            self.seek(start+0.01)
            return True

        if self.positionchooser.get_adjustment().get_property("upper") != duration:
            self.positionchooser.set_range(0.0, duration)
            self.save_config()
        end = self.endchooser.get_adjustment()
        delta = end.value-end.upper
        if delta <= -duration:
            delta = 0
        self.startchooser.set_range(0.0, duration)
        self.endchooser.set_range(0.0, duration)
        self.endchooser.set_value(duration+delta)
        self.positionchooser.set_value(position)
        self.positionchooser.queue_draw()
        return self.play_button.get_active()

    def about(self, sender):
        """show an about dialog"""
        about = gtk.AboutDialog()
        about.set_transient_for(self)
        about.set_logo(mygtk.iconfactory.get_icon("playitslowly", 128))
        about.set_name(NAME)
        about.set_version(VERSION)
        about.set_authors(["Jonas Wagner", "Elias Dorneles"])
        about.set_translator_credits(_("translator-credits"))
        about.set_copyright("Copyright (c) 2009 - 2011 Jonas Wagner")
        about.set_website(WEBSITE)
        about.set_website_label(WEBSITE)
        about.set_license("""
Copyright (C) 2009 - 2011 Jonas Wagner
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
""")
        about.run()
        about.destroy()
Example #8
0
class AppCli:
    def __init__(self, filepath, outfilepath, speed, sink):
        self.filepath = filepath
        self.outfilepath = outfilepath
        self.speed = speed
        self.sink = sink
        self.duration = None
        self.close = False

    def set_loop(self, loop):
        self.loop = loop

    def on_eos(self):
        self.close = True

    def read_duration(self, pipeline):
        try:
            duration_seconds = pipeline.query_duration(gst.FORMAT_TIME)[0] / 1000000000
            duration = timedelta(seconds=duration_seconds)
        except:
            return None
        else:
            return duration

    def read_position(self, pipeline):
        try:
            position_seconds = pipeline.query_position(gst.FORMAT_TIME)[0] / 1000000000
            position = timedelta(seconds=position_seconds)
        except:
            return None
        else:
            return position

    def prepare_pipeline(self):
        gstsink = gst.parse_bin_from_description(self.sink, True)
        self.pipeline = Pipeline(gstsink)
        self.pipeline.reset()
        self.pipeline.set_file("file://" + self.filepath)
        self.pipeline.set_speed(self.speed)
        self.pipeline.set_on_eos_cb(self.on_eos)

    def set_encoder(self, encoder):
        self.pipeline.set_encoder(encoder)

    def __monitor_progress(self, pipeline):
        while not self.close:
            if not self.duration:
                d = self.read_duration(pipeline)
                if d:
                    self.duration = d
                    input_duration = timedelta(seconds=d.total_seconds() * self.speed)
                    print "Original file duration: %s" % input_duration
            position = self.read_position(pipeline)
            if position:
                if self.duration:
                    print "Position: %s/%s %s[%%]" % (
                        position,
                        self.duration,
                        int(position.total_seconds() * 100 // self.duration.total_seconds()),
                    )
                else:
                    print "Position: %s/-" % position
            time.sleep(1)

    def save_file_thread(self):
        pipeline_save, b = self.pipeline.save_file(self.outfilepath)
        self.__monitor_progress(pipeline_save)
        print "Done"
        pipeline_save.set_state(gst.STATE_NULL)
        self.loop.quit()

    def play_file_thread(self):
        self.pipeline.play()
        self.__monitor_progress(self.pipeline)
        print "Done"
        self.pipeline.set_state(gst.STATE_NULL)
        self.loop.quit()
Example #9
0
    def __init__(self, sink, config):
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)

        self.set_title(NAME)

        try:
            self.set_icon(mygtk.iconfactory.get_icon("playitslowly", 128))
        except gobject.GError:
            print "could not load playitslowly icon"

        self.set_default_size(500, 200)
        self.set_border_width(5)

        self.vbox = gtk.VBox()
        self.accel_group = gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        self.pipeline = Pipeline(sink)

        self.filedialog = mygtk.FileChooserDialog(None, self,
                                                  gtk.FILE_CHOOSER_ACTION_OPEN)
        self.filedialog.connect("response", self.filechanged)
        self.filedialog.set_local_only(False)
        filechooserhbox = gtk.HBox()
        self.filechooser = gtk.FileChooserButton(self.filedialog)
        self.filechooser.set_local_only(False)
        filechooserhbox.pack_start(self.filechooser, True, True)
        self.recentbutton = gtk.Button(_("Recent"))
        self.recentbutton.connect("clicked", self.show_recent)
        filechooserhbox.pack_end(self.recentbutton, False, False)

        self.speedchooser = mygtk.TextScaleReset(
            gtk.Adjustment(1.00, 0.10, 4.0, 0.05, 0.05))
        self.speedchooser.scale.connect("value-changed", self.speedchanged)
        self.speedchooser.scale.connect("button-press-event", self.speedpress)
        self.speedchooser.scale.connect("button-release-event",
                                        self.speedrelease)
        self.speedchangeing = False

        self.pitchchooser = mygtk.TextScaleReset(
            gtk.Adjustment(0.0, -24.0, 24.0, 1.0, 1.0, 1.0))
        self.pitchchooser.scale.connect("value-changed", self.pitchchanged)

        self.pitchchooser_fine = mygtk.TextScaleReset(
            gtk.Adjustment(0.0, -50, 50, 1.0, 1.0, 1.0))
        self.pitchchooser_fine.scale.connect("value-changed",
                                             self.pitchchanged)

        self.positionchooser = mygtk.ClockScale(gtk.Adjustment(
            0.0, 0.0, 100.0))
        self.positionchooser.scale.connect("button-press-event",
                                           self.start_seeking)
        self.positionchooser.scale.connect("button-release-event",
                                           self.positionchanged)
        self.seeking = False

        self.startchooser = mygtk.TextScaleWithCurPos(
            self.positionchooser, gtk.Adjustment(0.0, 0, 100.0))
        self.startchooser.scale.connect("button-press-event",
                                        self.start_seeking)
        self.startchooser.scale.connect("button-release-event", self.seeked)
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['), gtk.gdk.CONTROL_MASK, ())
        self.startchooser.add_accelerator("clicked", self.accel_group,
                                          ord('['), 0, ())

        self.endchooser = mygtk.TextScaleWithCurPos(
            self.positionchooser, gtk.Adjustment(1.0, 0, 100.0, 0.01, 0.01))
        self.endchooser.scale.connect("button-press-event", self.start_seeking)
        self.endchooser.scale.connect("button-release-event", self.seeked)
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        gtk.gdk.CONTROL_MASK, ())
        self.endchooser.add_accelerator("clicked", self.accel_group, ord(']'),
                                        0, ())

        self.vbox.pack_start(filechooserhbox)
        self.vbox.pack_start(self.positionchooser)
        self.vbox.pack_start(
            mygtk.form([(_(u"Speed (times)"), self.speedchooser),
                        (_(u"Pitch (semitones)"), self.pitchchooser),
                        (_(u"Fine Pitch (cents)"), self.pitchchooser_fine),
                        (_(u"Start Position (seconds)"), self.startchooser),
                        (_(u"End Position (seconds)"), self.endchooser)]),
            False, False)

        buttonbox = gtk.HButtonBox()
        self.vbox.pack_end(buttonbox, False, False)

        self.play_button = gtk.ToggleButton(gtk.STOCK_MEDIA_PLAY)
        self.play_button.connect("toggled", self.play)
        self.play_button.set_use_stock(True)
        self.play_button.set_sensitive(False)
        buttonbox.pack_start(self.play_button)
        # make SPACE a shortcut for play/pause (CTRL-SPC would be better?)
        self.play_button.add_accelerator("clicked", self.accel_group, ord(' '),
                                         0, ())

        self.back_button = gtk.Button(gtk.STOCK_MEDIA_REWIND)
        self.back_button.connect("clicked", self.back)
        self.back_button.set_use_stock(True)
        self.back_button.set_sensitive(False)
        buttonbox.pack_start(self.back_button)

        self.volume_button = gtk.VolumeButton()
        self.volume_button.set_value(1.0)
        self.volume_button.set_relief(gtk.RELIEF_NORMAL)
        self.volume_button.connect("value-changed", self.volumechanged)
        buttonbox.pack_start(self.volume_button)

        self.save_as_button = gtk.Button(stock=gtk.STOCK_SAVE_AS)
        self.save_as_button.connect("clicked", self.save)
        self.save_as_button.set_sensitive(False)
        buttonbox.pack_start(self.save_as_button)

        button_about = gtk.Button(stock=gtk.STOCK_ABOUT)
        button_about.connect("clicked", self.about)
        buttonbox.pack_end(button_about)

        self.connect("key-release-event", self.key_release)

        self.add(self.vbox)
        self.connect("destroy", gtk.main_quit)

        self.config = config
        self.config_saving = False
        self.load_config()