Example #1
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][2]

    if option == "threshold":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "ratio":
        return config.getfloat("plugins", cfg_option, default)
Example #2
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][2]

    if option == "seekto":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "skipat":
        return config.getfloat("plugins", cfg_option, default)
Example #3
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][2]

    if option == "threshold":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "ratio":
        return config.getfloat("plugins", cfg_option, default)
Example #4
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][2]

    if option == "seekto":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "skipat":
        return config.getfloat("plugins", cfg_option, default)
Example #5
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][1]

    if option == "rate":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "tempo":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "pitch":
        return config.getfloat("plugins", cfg_option, default)
Example #6
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][1]

    if option == "rate":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "tempo":
        return config.getfloat("plugins", cfg_option, default)
    elif option == "pitch":
        return config.getfloat("plugins", cfg_option, default)
Example #7
0
 def do_set_property(self, property, v):
     if property.name == 'volume':
         self._volume = v
         if self.song and config.getboolean("player", "replaygain"):
             profiles = filter(None, self.replaygain_profiles)[0]
             fb_gain = config.getfloat("player", "fallback_gain")
             pa_gain = config.getfloat("player", "pre_amp_gain")
             scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
             v = min(10.0, max(0.0, v * scale)) # volume supports 0..10
         if self.bin:
             self._vol_element.set_property('volume', v)
     else:
         raise AttributeError
 def do_set_property(self, property, v):
     if property.name == 'volume':
         self._volume = v
         if self.song and config.getboolean("player", "replaygain"):
             profiles = filter(None, self.replaygain_profiles)[0]
             fb_gain = config.getfloat("player", "fallback_gain")
             pa_gain = config.getfloat("player", "pre_amp_gain")
             scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
             v = min(10.0, max(0.0, v * scale)) # volume supports 0..10
         if self.bin:
             self._vol_element.set_property('volume', v)
     else:
         raise AttributeError
Example #9
0
 def do_set_property(self, property, v):
     if property.name == 'volume':
         self._volume = v
         if self.song and config.getboolean("player", "replaygain"):
             profiles = filter(None, self.replaygain_profiles)[0]
             fb_gain = config.getfloat("player", "fallback_gain")
             pa_gain = config.getfloat("player", "pre_amp_gain")
             scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
             v = max(0.0, v * scale)
         v = min(100, int(v * 100))
         xine_set_param(self._stream, XINE_PARAM_AUDIO_AMP_LEVEL, v)
     else:
         raise AttributeError
Example #10
0
 def do_set_property(self, property, v):
     if property.name == 'volume':
         self._volume = v
         if self.song and config.getboolean("player", "replaygain"):
             profiles = filter(None, self.replaygain_profiles)[0]
             fb_gain = config.getfloat("player", "fallback_gain")
             pa_gain = config.getfloat("player", "pre_amp_gain")
             scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
             v = max(0.0, v * scale)
         v = min(100, int(v * 100))
         xine_set_param(self._stream, XINE_PARAM_AUDIO_AMP_LEVEL, v)
     else:
         raise AttributeError
Example #11
0
def bayesian_average(nums, c=None, m=None):
    """Returns the Bayesian average of an iterable of numbers,
    with parameters defaulting to config specific to ~#rating."""
    m = m or config.RATINGS.default
    c = c or config.getfloat("settings", "bayesian_rating_factor", 0.0)
    ret = float(m * c + sum(nums)) / (c + len(nums))
    return ret
Example #12
0
 def __refresh_album(self, menuitem, view):
     albums = self.__get_selected_albums()
     mag = config.getfloat("browsers", "covergrid_magnification", 3.)
     scale_factor = self.get_scale_factor() * mag
     for album in albums:
         album.scan_cover(True, scale_factor=scale_factor)
     self._refresh_albums(albums)
def bayesian_average(nums, c=None, m=None):
    """Returns the Bayesian average of an iterable of numbers,
    with parameters defaulting to config specific to ~#rating."""
    m = m or config.RATINGS.default
    c = c or config.getfloat("settings", "bayesian_rating_factor", 0.0)
    ret = float(m * c + sum(nums)) / (c + len(nums))
    return ret
Example #14
0
def slider_config(section, option, label, tooltip, lower=0, upper=1,
                 on_change_callback=None, label_value_callback=None):
    def on_reverted(*args):
        config.reset(section, option)
        scale.set_value(config.getfloat(section, option))

    def on_change(scale):
        value = scale.get_value()
        if on_change_callback:
            value = on_change_callback(value)
        scale.set_value(value)
        config.set(section, option, value)

    default = config.getfloat(section, option)

    scale = Gtk.HScale.new(Gtk.Adjustment(
                                       value=default,
                                       lower=lower, upper=upper))
    scale.set_value_pos(Gtk.PositionType.LEFT)
    scale.set_show_fill_level(True)
    scale.set_tooltip_text(_(tooltip))

    if label_value_callback:
        scale.connect('format-value', lambda _, value: label_value_callback(value))
    scale.connect('value-changed', on_change)

    revert = Gtk.Button()
    revert.add(Gtk.Image.new_from_icon_name(Icons.DOCUMENT_REVERT, Gtk.IconSize.BUTTON))
    revert.connect("clicked", on_reverted)

    lbl = Gtk.Label(label=label, use_underline=True)
    lbl.set_mnemonic_widget(scale)
    return lbl, scale, revert
Example #15
0
    def select_browser(self, activator, current, library, player,
                       restore=False):
        if isinstance(current, Gtk.RadioAction):
            current = current.get_current_value()
        Browser = browsers.get(current)
        config.set("memory", "browser", Browser.__name__)
        if self.browser:
            container = self.browser.__container
            self.browser.unpack(container, self.songpane)
            if self.browser.accelerators:
                self.remove_accel_group(self.browser.accelerators)
            container.destroy()
            self.browser.destroy()
        self.browser = Browser(library, True)
        self.browser.connect('songs-selected', self.__browser_cb)
        self.browser.connect('activated', self.__browser_activate)
        if restore:
            self.browser.restore()
            self.browser.activate()
        self.browser.finalize(restore)
        if self.browser.reordered:
            self.songlist.enable_drop()
        elif self.browser.dropped:
            self.songlist.enable_drop(False)
        else:
            self.songlist.disable_drop()
        if self.browser.accelerators:
            self.add_accel_group(self.browser.accelerators)

        container = self.browser.__container = self.browser.pack(self.songpane)

        # find a paned and save the position
        paned = None
        for widget in qltk.find_widgets(container, RPaned):
            if widget is not self.songpane:
                paned = widget
                break

        if paned:
            try:
                key = "%s_pos" % self.browser.__class__.__name__
                val = config.getfloat("browsers", key)
                # Use a minimum restore size
                val = max(val, 0.1)
            except:
                val = 0.4
            paned.connect(
                'notify::position', self.__browser_configure, self.browser)

            paned.set_relative(val)

        player.replaygain_profiles[1] = self.browser.replaygain_profiles
        player.volume = player.volume
        self.__browserbox.add(container)
        container.show()
        self.__hide_menus()
        self.__hide_headers()
        self.__refresh_size()
Example #16
0
    def _no_cover(self):
        """Returns a cairo surface representing a missing cover"""

        mag = config.getfloat("browsers", "covergrid_magnification", 3.)

        cover_size = get_cover_size()
        scale_factor = self.get_scale_factor() * mag
        pb = get_no_cover_pixbuf(cover_size, cover_size, scale_factor)
        return get_surface_for_pixbuf(self, pb)
Example #17
0
 def update_mag(klass):
     mag = config.getfloat("browsers", "covergrid_magnification", 3.)
     for covergrid in klass.instances():
         covergrid.__cover.set_property('width', get_cover_size() * mag + 8)
         covergrid.__cover.set_property('height',
             get_cover_size() * mag + 8)
         covergrid.view.set_item_width(get_cover_size() * mag + 8)
         covergrid.view.queue_resize()
         covergrid.redraw()
Example #18
0
 def test_get(self):
     config.set("foo", "int", "1")
     config.set("foo", "float", "1.25")
     config.set("foo", "str", "foobar")
     config.set("foo", "bool", "True")
     self.failUnlessEqual(config.getint("foo", "int"), 1)
     self.failUnlessEqual(config.getfloat("foo", "float"), 1.25)
     self.failUnlessEqual(config.get("foo", "str"), "foobar")
     self.failUnlessEqual(config.getboolean("foo", "bool"), True)
Example #19
0
    def __init__(self):
        for (key, text, func) in self.keys:
            val = config.getfloat("plugins", "randomalbum_%s" % key, 0.0)
            self.weights[key] = val

        use = config.getint("plugins", "randomalbum_use_weights", 0)
        self.use_weights = use
        delay = config.getint("plugins", "randomalbum_delay", 0)
        self.delay = delay
Example #20
0
 def update_mag(klass):
     mag = config.getfloat("browsers", "covergrid_magnification", 3.)
     for covergrid in klass.instances():
         covergrid.__cover.set_property('width', get_cover_size() * mag + 8)
         covergrid.__cover.set_property('height',
             get_cover_size() * mag + 8)
         covergrid.view.set_item_width(get_cover_size() * mag + 8)
         covergrid.view.queue_resize()
         covergrid.redraw()
Example #21
0
    def _no_cover(self) -> Optional[cairo.Surface]:
        """Returns a cairo surface representing a missing cover"""

        mag = config.getfloat("browsers", "covergrid_magnification", 3.)

        cover_size = get_cover_size()
        scale_factor = self.get_scale_factor() * mag
        pb = get_no_cover_pixbuf(cover_size, cover_size, scale_factor)
        return get_surface_for_pixbuf(self, pb)
Example #22
0
    def __init__(self):
        for (key, text, func) in self.keys:
            val = config.getfloat("plugins", "randomalbum_%s" % key, 0.0)
            self.weights[key] = val

        use = config.getint("plugins", "randomalbum_use_weights", 0)
        self.use_weights = use
        delay = config.getint("plugins", "randomalbum_delay", 0)
        self.delay = delay
Example #23
0
    def __init__(self, parent, player, library):
        super(TopBar, self).__init__()

        # play controls
        control_item = Gtk.ToolItem()
        self.insert(control_item, 0)
        t = PlayControls(player, library.librarian)
        self.volume = t.volume

        # only restore the volume in case it is managed locally, otherwise
        # this could affect the system volume
        if not player.has_external_volume:
            player.volume = config.getfloat("memory", "volume")

        connect_destroy(player, "notify::volume", self._on_volume_changed)
        control_item.add(t)

        self.insert(Gtk.SeparatorToolItem(), 1)

        info_item = Gtk.ToolItem()
        self.insert(info_item, 2)
        info_item.set_expand(True)

        box = Gtk.Box(spacing=6)
        info_item.add(box)
        qltk.add_css(self, "GtkToolbar {padding: 3px;}")

        self._pattern_box = Gtk.VBox()

        # song text
        info_pattern_path = os.path.join(quodlibet.get_user_dir(), "songinfo")
        text = SongInfo(library.librarian, player, info_pattern_path)
        self._pattern_box.pack_start(Align(text, border=3), True, True, 0)
        box.pack_start(self._pattern_box, True, True, 0)

        # cover image
        self.image = CoverImage(resize=True)
        connect_destroy(player, 'song-started', self.__new_song)

        # FIXME: makes testing easier
        if app.cover_manager:
            connect_destroy(
                app.cover_manager, 'cover-changed',
                self.__song_art_changed, library)

        box.pack_start(Align(self.image, border=2), False, True, 0)

        # On older Gtk+ (3.4, at least)
        # setting a margin on CoverImage leads to errors and result in the
        # QL window not being visible for some reason.
        assert self.image.props.margin == 0

        for child in self.get_children():
            child.show_all()

        context = self.get_style_context()
        context.add_class("primary-toolbar")
 def __set_pane_size(self):
     widgets = qltk.find_widgets(self.__container, RPaned)
     if widgets:
         paned = widgets[0]
         try:
             key = "%s_pos" % self.browser.__class__.__name__
             val = config.getfloat("browsers", key)
         except:
             val = 0.4
         paned.set_relative(val)
Example #25
0
 def mag_changed(mag):
     if self.mag_lock:
         return
     newmag = mag.get_value()
     oldmag = config.getfloat("browsers", "covergrid_magnification", 3.0)
     if newmag == oldmag:
         print_d("Covergrid magnification haven't changed: {0}".format(newmag))
         return
     print_d("Covergrid magnification update from {0} to {1}".format(oldmag, newmag))
     config.set("browsers", "covergrid_magnification", mag.get_value())
     browser.update_mag()
Example #26
0
    def calc_replaygain_volume(self, volume):
        """Returns a new float volume for the given volume.

        Takes into account the global active replaygain profile list,
        the user specified replaygain settings and the tags available
        for that song.

        Args:
            volume (float): 0.0..1.0
        Returns:
            float: adjusted volume, can be outside of 0.0..0.1
        """

        if self.song and config.getboolean("player", "replaygain"):
            profiles = list(filter(None, self.replaygain_profiles))[0]
            fb_gain = config.getfloat("player", "fallback_gain")
            pa_gain = config.getfloat("player", "pre_amp_gain")
            scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
        else:
            scale = 1
        return volume * scale
Example #27
0
    def calc_replaygain_volume(self, volume):
        """Returns a new float volume for the given volume.

        Takes into account the global active replaygain profile list,
        the user specified replaygain settings and the tags available
        for that song.

        Args:
            volume (float): 0.0..1.0
        Returns:
            float: adjusted volume, can be outside of 0.0..0.1
        """

        if self.song and config.getboolean("player", "replaygain"):
            profiles = listfilter(None, self.replaygain_profiles)[0]
            fb_gain = config.getfloat("player", "fallback_gain")
            pa_gain = config.getfloat("player", "pre_amp_gain")
            scale = self.song.replay_gain(profiles, pa_gain, fb_gain)
        else:
            scale = 1
        return volume * scale
    def test_bayesian_multiple_ratings(s):
        # separated from above to avoid caching
        c, r1, r2 = 5, 1.0, 0.5
        songs = [Fakesong({"~#rating": r1}), Fakesong({"~#rating": r2})]
        album = Album(songs[0])
        album.songs = set(songs)

        config.set("settings", "bayesian_rating_factor", float(c))
        s.failUnlessEqual(config.getfloat("settings", "bayesian_rating_factor"), float(c))
        expected = avg(c * [config.RATINGS.default] + [r1, r2])
        s.failUnlessEqual(album("~#rating:bav"), expected)
        s.failUnlessEqual(album("~#rating"), expected)
    def __init__(self, songs, library):
        super(WeightedPlaylist, self).__init__(songs, library)

        for key,_ in self.options["weights"]:
            val = config.getfloat("plugins", "weightedlibrary_%s" % key, 0.0)
            self.weights[key] = val
        for key,_,min_value,max_value in self.options["values"]:
            val = config.getfloat("plugins", "weightedlibrary_%s" % key, (min_value+max_value)/2.)
            self.weights[key] = val


        for key,val in self.weights.items():
            print "%s = %s" % (key,val)

        rater = ModifiedAveragedRater()
        # Raters are a weighted sum
        rater.add_rater(weight=self.weights["rating"], rater=SongRatingRater())
        rater.add_rater(weight=self.weights["tempo"], rater=BpmRater(target_bpm=self.weights["tempo_target"], spread=self.weights["tempo_spread"])) # Variety is between 0 and 50
        # Modifiers work multiplicatively
        rater.add_modifier(weight=3., rater=RepeaterRater())

        self.rater = rater
Example #30
0
    def test_bayesian_multiple_ratings(s):
        # separated from above to avoid caching
        c, r1, r2 = 5, 1.0, 0.5
        songs = [Fakesong({"~#rating": r1}), Fakesong({"~#rating": r2})]
        album = Album(songs[0])
        album.songs = set(songs)

        config.set("settings", "bayesian_rating_factor", float(c))
        s.failUnlessEqual(
            config.getfloat("settings", "bayesian_rating_factor"), float(c))
        expected = avg(c * [config.RATINGS.default] + [r1, r2])
        s.failUnlessEqual(album("~#rating:bav"), expected)
        s.failUnlessEqual(album("~#rating"), expected)
Example #31
0
 def mag_changed(mag):
     if self.mag_lock:
         return
     newmag = mag.get_value()
     oldmag = config.getfloat("browsers", "covergrid_magnification", 3.)
     if newmag == oldmag:
         print_d("Covergrid magnification haven't changed: {0}".format(
             newmag))
         return
     print_d('Covergrid magnification update from {0} to {1}'.format(
         oldmag, newmag))
     config.set("browsers", "covergrid_magnification", mag.get_value())
     browser.update_mag()
Example #32
0
    def __init__(self, parent, player, library):
        super(TopBar, self).__init__()

        # play controls
        control_item = Gtk.ToolItem()
        self.insert(control_item, 0)
        t = PlayControls(player, library.librarian)
        self.volume = t.volume

        # only restore the volume in case it is managed locally, otherwise
        # this could affect the system volume
        if not player.has_external_volume:
            player.volume = config.getfloat("memory", "volume")

        self.volume.connect("value-changed", self._on_volume_changed)
        control_item.add(t)

        self.insert(Gtk.SeparatorToolItem(), 1)

        info_item = Gtk.ToolItem()
        self.insert(info_item, 2)
        info_item.set_expand(True)

        box = Gtk.Box(spacing=6)
        info_item.add(box)
        qltk.add_css(self, "GtkToolbar {padding: 3px;}")

        # song text
        info_pattern_path = os.path.join(const.USERDIR, "songinfo")
        text = SongInfo(library.librarian, player, info_pattern_path)
        box.pack_start(Align(text, border=3), True, True, 0)

        # cover image
        self.image = CoverImage(resize=True)
        connect_destroy(player, 'song-started', self.__new_song)

        # FIXME: makes testing easier
        if app.cover_manager:
            connect_destroy(
                app.cover_manager, 'cover-changed',
                self.__song_art_changed, library)

        self.image.props.margin = 2
        box.pack_start(self.image, False, True, 0)

        for child in self.get_children():
            child.show_all()

        context = self.get_style_context()
        context.add_class("primary-toolbar")
Example #33
0
    def __set_pane_size(self):
        sub = self.__container
        if not isinstance(self.__container, RPaned):
            for child in self.__container.get_children():
                if isinstance(child, RPaned):
                    sub = child

        if isinstance(sub, RPaned):
            try:
                key = "%s_pos" % self.browser.__class__.__name__
                val = config.getfloat("browsers", key)
            except:
                val = 0.4
            sub.set_relative(val)
Example #34
0
    def test_basic(self):
        self.failUnless(config.get("memory", "foobar", None) is None)

        p = x.ConfigRVPaned("memory", "foobar", 0.75)
        p.pack1(Gtk.Button())
        p.pack2(Gtk.Button())

        with visible(p, width=200, height=200) as p:
            self.failUnlessAlmostEqual(p.get_relative(), 0.75, 2)
            p.props.position = 20
            self.failUnlessAlmostEqual(p.get_relative(), 0.10, 2)

        config_value = config.getfloat("memory", "foobar")
        self.failUnlessAlmostEqual(config_value, 0.10, 2)
    def __init__(self, device):
        super(Volume, self).__init__(size=Gtk.IconSize.MENU, use_symbolic=True)

        self.set_relief(Gtk.ReliefStyle.NORMAL)
        self.set_adjustment(Gtk.Adjustment(0, 0, 1, 0.05, 0.1, 0))

        self.connect('value-changed', self.__volume_changed, device)
        device.connect('notify::volume', self.__volume_notify)
        self.set_value(config.getfloat("memory", "volume"))

        replaygain_menu = ReplayGainMenu(device)
        self.connect('popup-menu', self.__popup, replaygain_menu)
        self.connect_object('button-press-event', self.__volume_button_press,
                            replaygain_menu)
Example #36
0
    def test_basic(self):
        self.failUnless(config.get("memory", "foobar", None) is None)

        p = ConfigRVPaned("memory", "foobar", 0.75)
        p.pack1(Gtk.Button())
        p.pack2(Gtk.Button())

        with visible(p, width=200, height=200) as p:
            self.failUnlessAlmostEqual(p.get_relative(), 0.75, 2)
            p.props.position = 20
            self.failUnlessAlmostEqual(p.get_relative(), 0.10, 2)

        config_value = config.getfloat("memory", "foobar")
        self.failUnlessAlmostEqual(config_value, 0.10, 2)
Example #37
0
    def __init__(self, parent, player, library):
        super(TopBar, self).__init__()

        # play controls
        control_item = Gtk.ToolItem()
        self.insert(control_item, 0)
        t = PlayControls(player, library.librarian)
        self.volume = t.volume

        # only restore the volume in case it is managed locally, otherwise
        # this could affect the system volume
        if not player.has_external_volume:
            player.volume = config.getfloat("memory", "volume")

        self.volume.connect("value-changed", self._on_volume_changed)
        control_item.add(t)

        self.insert(Gtk.SeparatorToolItem(), 1)

        info_item = Gtk.ToolItem()
        self.insert(info_item, 2)
        info_item.set_expand(True)

        box = Gtk.Box(spacing=6)
        info_item.add(box)
        qltk.add_css(self, "GtkToolbar {padding: 3px;}")

        # song text
        info_pattern_path = os.path.join(const.USERDIR, "songinfo")
        text = SongInfo(library.librarian, player, info_pattern_path)
        box.pack_start(Align(text, border=3), True, True, 0)

        # cover image
        self.image = CoverImage(resize=True)
        connect_destroy(player, 'song-started', self.__new_song)

        # FIXME: makes testing easier
        if app.cover_manager:
            connect_destroy(app.cover_manager, 'cover-changed',
                            self.__song_art_changed, library)

        self.image.props.margin = 2
        box.pack_start(self.image, False, True, 0)

        for child in self.get_children():
            child.show_all()

        context = self.get_style_context()
        context.add_class("primary-toolbar")
Example #38
0
    def _set_color(self, _widget, validator):
        value = validator(self.get_text())
        default = self._default_color()
        amount = config.getfloat("settings", "validator_colorise")
        if value is True:
            color = mix(default, self.VALID, amount)
        elif value is False:
            color = mix(default, self.INVALID, amount)
        else:
            color = Gdk.RGBA(default.red, default.green, default.blue, self.ALPHA)

        if color and self.get_property('sensitive'):
            self.override_color(Gtk.StateType.NORMAL, color)
        else:
            self.override_color(Gtk.StateType.NORMAL, None)
Example #39
0
    def __init__(self, device):
        super(Volume, self).__init__(size=Gtk.IconSize.MENU, use_symbolic=True)

        self.set_relief(Gtk.ReliefStyle.NORMAL)
        self.set_adjustment(Gtk.Adjustment.new(0, 0, 1, 0.05, 0.1, 0))

        self.connect('value-changed', self.__volume_changed, device)
        device.connect('notify::volume', self.__volume_notify)
        self.set_value(config.getfloat("memory", "volume"))

        replaygain_menu = ReplayGainMenu(device)
        replaygain_menu.attach_to_widget(self, None)
        self.connect('popup-menu', self.__popup, replaygain_menu)
        connect_obj(self, 'button-press-event', self.__volume_button_press,
                            replaygain_menu)
Example #40
0
    def __init__(self, song_scroller, qexpander):
        super(SongListPaned, self).__init__()

        self.pack1(song_scroller, resize=True, shrink=False)
        self.pack2(qexpander, resize=True, shrink=False)

        self.set_relative(config.getfloat("memory", "queue_position", 0.75))
        self.connect(
            'notify::position', self._changed, "memory", "queue_position")

        self._handle_position = self.get_relative()
        qexpander.connect('notify::visible', self._expand_or)
        qexpander.connect('notify::expanded', self._expand_or)
        qexpander.connect('draw', self._check_minimize)

        self.connect("button-press-event", self._on_button_press)
        self.connect('notify', self._moved_pane_handle)
Example #41
0
    def __init__(self, song_scroller, qexpander):
        super().__init__()

        self.pack1(song_scroller, resize=True, shrink=False)
        self.pack2(qexpander, resize=True, shrink=False)

        self.set_relative(config.getfloat("memory", "queue_position", 0.75))
        self.connect('notify::position', self._changed, "memory",
                     "queue_position")

        self._handle_position = self.get_relative()
        qexpander.connect('notify::visible', self._expand_or)
        qexpander.connect('notify::expanded', self._expand_or)
        qexpander.connect('draw', self._check_minimize)

        self.connect("button-press-event", self._on_button_press)
        self.connect('notify', self._moved_pane_handle)
Example #42
0
    def __init__(self, device):
        super(Volume, self).__init__()

        self.props.size = SUBSIZE
        self.set_relief(gtk.RELIEF_NORMAL)
        self.set_adjustment(gtk.Adjustment(0, 0, 1, 0.05, 0.1, 0))

        self.connect('value-changed', self.__volume_changed, device)
        device.connect('notify::volume', self.__volume_notify)
        self.set_value(config.getfloat("memory", "volume"))

        self.show_all()

        replaygain_menu = ReplayGainMenu(device)
        self.connect('popup-menu', self.__popup, replaygain_menu)
        self.connect_object('button-press-event', self.__volume_button_press,
                            replaygain_menu)
Example #43
0
    def _update_row(self, filter_model, iter_):
        sort_model = filter_model.get_model()
        model = sort_model.get_model()
        iter_ = filter_model.convert_iter_to_child_iter(iter_)
        iter_ = sort_model.convert_iter_to_child_iter(iter_)
        tref = Gtk.TreeRowReference.new(model, model.get_path(iter_))
        mag = config.getfloat("browsers", "covergrid_magnification", 3.)

        def callback():
            path = tref.get_path()
            if path is not None:
                model.row_changed(path, model.get_iter(path))
            # XXX: icon view seems to ignore row_changed signals for pixbufs..
            self.queue_resize()

        item = model.get_value(iter_)
        scale_factor = self.get_scale_factor() * mag
        item.scan_cover(scale_factor=scale_factor,
                        callback=callback,
                        cancel=self._cover_cancel)
Example #44
0
    def _update_row(self, filter_model, iter_):
        sort_model = filter_model.get_model()
        model = sort_model.get_model()
        iter_ = filter_model.convert_iter_to_child_iter(iter_)
        iter_ = sort_model.convert_iter_to_child_iter(iter_)
        tref = Gtk.TreeRowReference.new(model, model.get_path(iter_))
        mag = config.getfloat("browsers", "covergrid_magnification", 3.)

        def callback():
            path = tref.get_path()
            if path is not None:
                model.row_changed(path, model.get_iter(path))
            # XXX: icon view seems to ignore row_changed signals for pixbufs..
            self.queue_draw()

        item = model.get_value(iter_)
        scale_factor = self.get_scale_factor() * mag
        item.scan_cover(scale_factor=scale_factor,
                        callback=callback,
                        cancel=self._cover_cancel)
Example #45
0
    def __end(self, player, song, ended, librarian, pl):
        if song is not None and not song.multisong:
            if ended:
                config.set("memory", "seek", player.get_position())
            else:
                config.set("memory", "seek", 0)

            playcount_minimum_length = config.getfloat(
                "player", "playcount_minimum_length_proportion") * int(song.get(
                "~#length", 1))

            if self.elapsed >= playcount_minimum_length:
                song["~#lastplayed"] = int(time.time())
                song["~#playcount"] = song.get("~#playcount", 0) + 1
                self.__changed(librarian, song)
            elif pl.current is not song:
                if not player.error:
                    song["~#skipcount"] = song.get("~#skipcount", 0) + 1
                    self.__changed(librarian, song)
        else:
            config.set("memory", "seek", 0)
Example #46
0
    def __browser_cb(self, browser, songs, sorted, library, player):
        if browser.background:
            bg = background_filter()
            if bg:
                songs = filter(bg, songs)
        self.songlist.set_songs(songs, sorted)

        # After the first time the browser activates, which should always
        # happen if we start up and restore, restore the playing song.
        # Because the browser has send us songs we can be sure it has
        # registered all its libraries.
        if self.__first_browser_set:
            self.__first_browser_set = False

            song = library.librarian.get(config.get("memory", "song"))
            seek_pos = config.getfloat("memory", "seek", 0)
            config.set("memory", "seek", 0)
            if song is not None:
                player.setup(self.playlist, song, seek_pos)

            if self.__restore_cb:
                self.__restore_cb()
                self.__restore_cb = None
Example #47
0
    def __browser_cb(self, browser, songs, sorted, library, player):
        if browser.background:
            bg = background_filter()
            if bg:
                songs = filter(bg, songs)
        self.songlist.set_songs(songs, sorted)

        # After the first time the browser activates, which should always
        # happen if we start up and restore, restore the playing song.
        # Because the browser has send us songs we can be sure it has
        # registered all its libraries.
        if self.__first_browser_set:
            self.__first_browser_set = False

            song = library.librarian.get(config.get("memory", "song"))
            seek_pos = config.getfloat("memory", "seek", 0)
            config.set("memory", "seek", 0)
            if song is not None:
                player.setup(self.playlist, song, seek_pos)

            if self.__restore_cb:
                self.__restore_cb()
                self.__restore_cb = None
Example #48
0
def get_cfg(option):
    cfg_option = "%s_%s" % (_PLUGIN_ID, option)
    default = _SETTINGS[option][2]
    return config.getfloat("plugins", cfg_option, default)
Example #49
0
 def __init__(self, section, option, default, *args, **kwargs):
     super(ConfigRPaned, self).__init__(*args, **kwargs)
     self.set_relative(config.getfloat(section, option, default))
     self.connect('notify::position', self.__changed, section, option)
Example #50
0
        def __init__(self):
            super(PreferencesWindow.Player, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Playback")

            # player backend
            if app.player and hasattr(app.player, 'PlayerPreferences'):
                player_prefs = app.player.PlayerPreferences()
                f = qltk.Frame(_("Output Configuration"), child=player_prefs)
                self.pack_start(f, False, True, 0)

            # replaygain
            fallback_gain = config.getfloat("player", "fallback_gain", 0.0)
            adj = Gtk.Adjustment.new(fallback_gain, -12.0, 12.0, 0.5, 0.5, 0.0)
            fb_spin = Gtk.SpinButton(adjustment=adj)
            fb_spin.set_digits(1)
            fb_spin.connect('changed', self.__changed,
                            'player', 'fallback_gain')
            fb_spin.set_tooltip_text(
                _("If no Replay Gain information is available "
                  "for a song, scale the volume by this value"))

            fb_label = Gtk.Label(label=_("_Fall-back gain (dB):"))
            fb_label.set_use_underline(True)
            fb_label.set_mnemonic_widget(fb_spin)

            pre_amp_gain = config.getfloat("player", "pre_amp_gain", 0.0)
            adj = Gtk.Adjustment.new(pre_amp_gain, -6, 6, 0.5, 0.5, 0.0)
            adj.connect('value-changed', self.__changed,
                        'player', 'pre_amp_gain')
            pre_spin = Gtk.SpinButton(adjustment=adj)
            pre_spin.set_digits(1)
            pre_spin.set_tooltip_text(
                _("Scale volume for all songs by this value, "
                  "as long as the result will not clip"))

            pre_label = Gtk.Label(label=_("_Pre-amp gain (dB):"))
            pre_label.set_use_underline(True)
            pre_label.set_mnemonic_widget(pre_spin)

            widgets = [pre_label, pre_spin, fb_label, fb_spin]
            c = CCB(_("_Enable Replay Gain volume adjustment"),
                    "player", "replaygain", populate=True)
            c.connect('toggled', self.__toggled_gain, widgets)

            # packing
            table = Gtk.Table.new(3, 2, False)
            table.set_col_spacings(6)
            table.set_row_spacings(6)

            table.attach(c, 0, 2, 0, 1)
            fb_label.set_alignment(0, 0.5)
            table.attach(fb_label, 0, 1, 1, 2,
                         xoptions=Gtk.AttachOptions.FILL)
            pre_label.set_alignment(0, 0.5)
            table.attach(pre_label, 0, 1, 2, 3,
                         xoptions=Gtk.AttachOptions.FILL)

            fb_align = Align(halign=Gtk.Align.START)
            fb_align.add(fb_spin)
            table.attach(fb_align, 1, 2, 1, 2)

            pre_align = Align(halign=Gtk.Align.START)
            pre_align.add(pre_spin)
            table.attach(pre_align, 1, 2, 2, 3)

            f = qltk.Frame(_("Replay Gain Volume Adjustment"), child=table)

            c.emit('toggled')

            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Example #51
0
    def __init_pipeline(self):
        """Creates a gstreamer pipeline. Returns True on success."""

        if self.bin:
            return True

        # reset error state
        self.error = False

        pipeline = config.get("player", "gst_pipeline")
        try:
            pipeline, self._pipeline_desc = GStreamerSink(pipeline)
        except PlayerError as e:
            self._error(e)
            return False

        if self._use_eq and Gst.ElementFactory.find('equalizer-10bands'):
            # The equalizer only operates on 16-bit ints or floats, and
            # will only pass these types through even when inactive.
            # We push floats through to this point, then let the second
            # audioconvert handle pushing to whatever the rest of the
            # pipeline supports. As a bonus, this seems to automatically
            # select the highest-precision format supported by the
            # rest of the chain.
            filt = Gst.ElementFactory.make('capsfilter', None)
            filt.set_property('caps',
                              Gst.Caps.from_string('audio/x-raw,format=F32LE'))
            eq = Gst.ElementFactory.make('equalizer-10bands', None)
            self._eq_element = eq
            self.update_eq_values()
            conv = Gst.ElementFactory.make('audioconvert', None)
            resample = Gst.ElementFactory.make('audioresample', None)
            pipeline = [filt, eq, conv, resample] + pipeline

        # playbin2 has started to control the volume through pulseaudio,
        # which means the volume property can change without us noticing.
        # Use our own volume element for now until this works with PA.
        self._int_vol_element = Gst.ElementFactory.make('volume', None)
        pipeline.insert(0, self._int_vol_element)

        # Get all plugin elements and append audio converters.
        # playbin already includes one at the end
        plugin_pipeline = []
        for plugin in self._get_plugin_elements():
            plugin_pipeline.append(plugin)
            plugin_pipeline.append(
                Gst.ElementFactory.make('audioconvert', None))
            plugin_pipeline.append(
                Gst.ElementFactory.make('audioresample', None))
        pipeline = plugin_pipeline + pipeline

        bufbin = Gst.Bin()
        for element in pipeline:
            assert element is not None, pipeline
            bufbin.add(element)

        if len(pipeline) > 1:
            if not link_many(pipeline):
                print_w("Linking the GStreamer pipeline failed")
                self._error(
                    PlayerError(_("Could not create GStreamer pipeline")))
                return False

        # see if the sink provides a volume property, if yes, use it
        sink_element = pipeline[-1]
        if isinstance(sink_element, Gst.Bin):
            sink_element = iter_to_list(sink_element.iterate_recurse)[-1]

        self._ext_vol_element = None
        if hasattr(sink_element.props, "volume"):
            self._ext_vol_element = sink_element

            # In case we use the sink volume directly we can increase buffering
            # without affecting the volume change delay too much and safe some
            # CPU time... (2x default for now).
            if hasattr(sink_element.props, "buffer_time"):
                sink_element.set_property("buffer-time", 400000)

            def ext_volume_notify(*args):
                # gets called from a thread
                GLib.idle_add(self.notify, "volume")

            self._ext_vol_element.connect("notify::volume", ext_volume_notify)

        self._ext_mute_element = None
        if hasattr(sink_element.props, "mute") and \
                sink_element.get_factory().get_name() != "directsoundsink":
            # directsoundsink has a mute property but it doesn't work
            # https://bugzilla.gnome.org/show_bug.cgi?id=755106
            self._ext_mute_element = sink_element

            def mute_notify(*args):
                # gets called from a thread
                GLib.idle_add(self.notify, "mute")

            self._ext_mute_element.connect("notify::mute", mute_notify)

        # Make the sink of the first element the sink of the bin
        gpad = Gst.GhostPad.new('sink', pipeline[0].get_static_pad('sink'))
        bufbin.add_pad(gpad)

        bin_ = Gst.ElementFactory.make('playbin', None)
        assert bin_

        self.bin = BufferingWrapper(bin_, self)
        self._seeker = Seeker(self.bin, self)

        bus = bin_.get_bus()
        bus.add_signal_watch()
        self.__bus_id = bus.connect('message', self.__message, self._librarian)

        self.__atf_id = self.bin.connect('about-to-finish',
            self.__about_to_finish)

        # set buffer duration
        duration = config.getfloat("player", "gst_buffer")
        self._set_buffer_duration(int(duration * 1000))

        # connect playbin to our pluing/volume/eq pipeline
        self.bin.set_property('audio-sink', bufbin)

        # by default playbin will render video -> suppress using fakesink
        fakesink = Gst.ElementFactory.make('fakesink', None)
        self.bin.set_property('video-sink', fakesink)

        # disable all video/text decoding in playbin
        GST_PLAY_FLAG_VIDEO = 1 << 0
        GST_PLAY_FLAG_TEXT = 1 << 2
        flags = self.bin.get_property("flags")
        flags &= ~(GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT)
        self.bin.set_property("flags", flags)

        if not self.has_external_volume:
            # Restore volume/ReplayGain and mute state
            self.volume = self._volume
            self.mute = self._mute

        # ReplayGain information gets lost when destroying
        self._reset_replaygain()

        if self.song:
            self.bin.set_property('uri', self.song("~uri"))

        return True
Example #52
0
        def ratings_vbox(self):
            """Returns a new VBox containing all ratings widgets"""
            vb = Gtk.VBox(spacing=6)

            # Default Rating
            model = Gtk.ListStore(float)
            default_combo = Gtk.ComboBox(model=model)
            default_lab = Gtk.Label(label=_("_Default rating:"))
            default_lab.set_use_underline(True)
            default_lab.set_alignment(0, 0.5)

            def draw_rating(column, cell, model, it, data):
                num = model[it][0]
                text = "%0.2f: %s" % (num, util.format_rating(num))
                cell.set_property('text', text)

            def default_rating_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.default = model[it][0]
                qltk.redraw_all_toplevels()

            def populate_default_rating_model(combo, num):
                model = combo.get_model()
                model.clear()
                deltas = []
                default = RATINGS.default
                precision = RATINGS.precision
                for i in range(0, num + 1):
                    r = i * precision
                    model.append(row=[r])
                    deltas.append((abs(default - r), i))
                active = sorted(deltas)[0][1]
                print_d("Choosing #%d (%.2f), closest to current %.2f"
                        % (active, precision * active, default))
                combo.set_active(active)

            cell = Gtk.CellRendererText()
            default_combo.pack_start(cell, True)
            default_combo.set_cell_data_func(cell, draw_rating, None)
            default_combo.connect('changed', default_rating_changed, model)
            default_lab.set_mnemonic_widget(default_combo)

            def refresh_default_combo(num):
                populate_default_rating_model(default_combo, num)

            # Rating Scale
            model = Gtk.ListStore(int)
            scale_combo = Gtk.ComboBox(model=model)
            scale_lab = Gtk.Label(label=_("Rating _scale:"))
            scale_lab.set_use_underline(True)
            scale_lab.set_mnemonic_widget(scale_combo)

            cell = Gtk.CellRendererText()
            scale_combo.pack_start(cell, False)
            num = RATINGS.number
            for i in [1, 2, 3, 4, 5, 6, 8, 10]:
                it = model.append(row=[i])
                if i == num:
                    scale_combo.set_active_iter(it)

            def draw_rating_scale(column, cell, model, it, data):
                num_stars = model[it][0]
                text = "%d: %s" % (num_stars, RATINGS.full_symbol * num_stars)
                cell.set_property('text', text)

            def rating_scale_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.number = num = model[it][0]
                refresh_default_combo(num)

            refresh_default_combo(RATINGS.number)
            scale_combo.set_cell_data_func(cell, draw_rating_scale, None)
            scale_combo.connect('changed', rating_scale_changed, model)

            default_align = Align(halign=Gtk.Align.START)
            default_align.add(default_lab)
            scale_align = Align(halign=Gtk.Align.START)
            scale_align.add(scale_lab)

            grid = Gtk.Grid(column_spacing=6, row_spacing=6)
            grid.add(scale_align)
            grid.add(scale_combo)
            grid.attach(default_align, 0, 1, 1, 1)
            grid.attach(default_combo, 1, 1, 1, 1)
            vb.pack_start(grid, False, False, 6)

            # Bayesian Factor
            bayesian_factor = config.getfloat("settings",
                                              "bayesian_rating_factor", 0.0)
            adj = Gtk.Adjustment.new(bayesian_factor, 0.0, 10.0, 0.5, 0.5, 0.0)
            bayes_spin = Gtk.SpinButton(adjustment=adj, numeric=True)
            bayes_spin.set_digits(1)
            bayes_spin.connect('changed', self.__changed_and_signal_library,
                               'settings', 'bayesian_rating_factor')
            bayes_spin.set_tooltip_text(
                _("Bayesian Average factor (C) for aggregated ratings.\n"
                  "0 means a conventional average, higher values mean that "
                  "albums with few tracks will have less extreme ratings. "
                  "Changing this value triggers a re-calculation for all "
                  "albums."))
            bayes_label = Gtk.Label(label=_("_Bayesian averaging amount:"))
            bayes_label.set_use_underline(True)
            bayes_label.set_mnemonic_widget(bayes_spin)

            # Save Ratings
            hb = Gtk.HBox(spacing=6)
            hb.pack_start(bayes_label, False, True, 0)
            hb.pack_start(bayes_spin, False, True, 0)
            vb.pack_start(hb, True, True, 0)
            cb = CCB(_("Save ratings and play _counts"),
                     "editing", "save_to_songs", populate=True)
            vb.pack_start(cb, True, True, 0)
            hb = Gtk.HBox(spacing=6)
            lab = Gtk.Label(label=_("_Email:"))
            entry = UndoEntry()
            entry.set_tooltip_text(_("Ratings and play counts will be set "
                                     "for this email address"))
            entry.set_text(config.get("editing", "save_email"))
            entry.connect('changed', self.__changed, 'editing', 'save_email')
            hb.pack_start(lab, False, True, 0)
            hb.pack_start(entry, True, True, 0)
            lab.set_mnemonic_widget(entry)
            lab.set_use_underline(True)
            vb.pack_start(hb, True, True, 0)

            return vb
Example #53
0
    def __init_pipeline(self):
        """Creates a gstreamer pipeline. Returns True on success."""

        if self.bin:
            return True

        # reset error state
        self.error = False

        pipeline = config.get("player", "gst_pipeline")
        try:
            pipeline, self._pipeline_desc = GStreamerSink(pipeline)
        except PlayerError as e:
            self._error(e)
            return False

        if self._use_eq and Gst.ElementFactory.find('equalizer-10bands'):
            # The equalizer only operates on 16-bit ints or floats, and
            # will only pass these types through even when inactive.
            # We push floats through to this point, then let the second
            # audioconvert handle pushing to whatever the rest of the
            # pipeline supports. As a bonus, this seems to automatically
            # select the highest-precision format supported by the
            # rest of the chain.
            filt = Gst.ElementFactory.make('capsfilter', None)
            filt.set_property('caps',
                              Gst.Caps.from_string('audio/x-raw,format=F32LE'))
            eq = Gst.ElementFactory.make('equalizer-10bands', None)
            self._eq_element = eq
            self.update_eq_values()
            conv = Gst.ElementFactory.make('audioconvert', None)
            resample = Gst.ElementFactory.make('audioresample', None)
            pipeline = [filt, eq, conv, resample] + pipeline

        # playbin2 has started to control the volume through pulseaudio,
        # which means the volume property can change without us noticing.
        # Use our own volume element for now until this works with PA.
        self._int_vol_element = Gst.ElementFactory.make('volume', None)
        pipeline.insert(0, self._int_vol_element)

        # Get all plugin elements and append audio converters.
        # playbin already includes one at the end
        plugin_pipeline = []
        for plugin in self._get_plugin_elements():
            plugin_pipeline.append(plugin)
            plugin_pipeline.append(
                Gst.ElementFactory.make('audioconvert', None))
            plugin_pipeline.append(
                Gst.ElementFactory.make('audioresample', None))
        pipeline = plugin_pipeline + pipeline

        bufbin = Gst.Bin()
        for element in pipeline:
            assert element is not None, pipeline
            bufbin.add(element)

        if len(pipeline) > 1:
            if not link_many(pipeline):
                print_w("Linking the GStreamer pipeline failed")
                self._error(
                    PlayerError(_("Could not create GStreamer pipeline")))
                return False

        # see if the sink provides a volume property, if yes, use it
        sink_element = pipeline[-1]
        if isinstance(sink_element, Gst.Bin):
            sink_element = iter_to_list(sink_element.iterate_recurse)[-1]

        self._ext_vol_element = None
        if hasattr(sink_element.props, "volume"):
            self._ext_vol_element = sink_element

            # In case we use the sink volume directly we can increase buffering
            # without affecting the volume change delay too much and safe some
            # CPU time... (2x default for now).
            if hasattr(sink_element.props, "buffer_time"):
                sink_element.set_property("buffer-time", 400000)

            def ext_volume_notify(*args):
                # gets called from a thread
                GLib.idle_add(self.notify, "volume")

            self._ext_vol_element.connect("notify::volume", ext_volume_notify)

        self._ext_mute_element = None
        if hasattr(sink_element.props, "mute") and \
                sink_element.get_factory().get_name() != "directsoundsink":
            # directsoundsink has a mute property but it doesn't work
            # https://bugzilla.gnome.org/show_bug.cgi?id=755106
            self._ext_mute_element = sink_element

            def mute_notify(*args):
                # gets called from a thread
                GLib.idle_add(self.notify, "mute")

            self._ext_mute_element.connect("notify::mute", mute_notify)

        # Make the sink of the first element the sink of the bin
        gpad = Gst.GhostPad.new('sink', pipeline[0].get_static_pad('sink'))
        bufbin.add_pad(gpad)

        bin_ = Gst.ElementFactory.make('playbin', None)
        assert bin_

        self.bin = BufferingWrapper(bin_, self)
        self._seeker = Seeker(self.bin, self)

        bus = bin_.get_bus()
        bus.add_signal_watch()
        self.__bus_id = bus.connect('message', self.__message, self._librarian)

        self.__atf_id = self.bin.connect('about-to-finish',
                                         self.__about_to_finish)

        # set buffer duration
        duration = config.getfloat("player", "gst_buffer")
        self._set_buffer_duration(int(duration * 1000))

        # connect playbin to our pluing/volume/eq pipeline
        self.bin.set_property('audio-sink', bufbin)

        # by default playbin will render video -> suppress using fakesink
        fakesink = Gst.ElementFactory.make('fakesink', None)
        self.bin.set_property('video-sink', fakesink)

        # disable all video/text decoding in playbin
        GST_PLAY_FLAG_VIDEO = 1 << 0
        GST_PLAY_FLAG_TEXT = 1 << 2
        flags = self.bin.get_property("flags")
        flags &= ~(GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT)
        self.bin.set_property("flags", flags)

        # find the (uri)decodebin after setup and use autoplug-sort
        # to sort elements like decoders
        def source_setup(*args):
            def autoplug_sort(decode, pad, caps, factories):
                def set_prio(x):
                    i, f = x
                    i = {"mad": -1, "mpg123audiodec": -2}.get(f.get_name(), i)
                    return (i, f)

                return list(
                    zip(*sorted(map(set_prio, enumerate(factories)))))[1]

            for e in iter_to_list(self.bin.iterate_recurse):
                try:
                    e.connect("autoplug-sort", autoplug_sort)
                except TypeError:
                    pass
                else:
                    break

        self.bin.connect("source-setup", source_setup)

        if not self.has_external_volume:
            # Restore volume/ReplayGain and mute state
            self.volume = self._volume
            self.mute = self._mute

        # ReplayGain information gets lost when destroying
        self._reset_replaygain()

        if self.song:
            self.bin.set_property('uri', self.song("~uri"))

        return True
Example #54
0
    def __init__(self, player, debug=False):
        super(GstPlayerPreferences, self).__init__(spacing=6)

        e = UndoEntry()
        e.set_tooltip_text(_("The GStreamer output pipeline used for "
                "playback. Leave blank for the default pipeline. "
                "In case the pipeline contains a sink, "
                "it will be used instead of the default one."))

        e.set_text(config.get('player', 'gst_pipeline'))

        def changed(entry):
            config.set('player', 'gst_pipeline', entry.get_text())
        e.connect('changed', changed)

        pipe_label = Gtk.Label(label=_('_Output pipeline:'))
        pipe_label.set_use_underline(True)
        pipe_label.set_mnemonic_widget(e)

        apply_button = Gtk.Button(stock=Gtk.STOCK_APPLY)

        def format_buffer(scale, value):
            return _("%.1f seconds") % value

        def scale_changed(scale):
            duration_msec = int(scale.get_value() * 1000)
            player._set_buffer_duration(duration_msec)

        duration = config.getfloat("player", "gst_buffer")
        scale = Gtk.HScale.new(
            Gtk.Adjustment(value=duration, lower=0.2, upper=10))
        scale.set_value_pos(Gtk.PositionType.RIGHT)
        scale.set_show_fill_level(True)
        scale.connect('format-value', format_buffer)
        scale.connect('value-changed', scale_changed)

        buffer_label = Gtk.Label(label=_('_Buffer duration:'))
        buffer_label.set_use_underline(True)
        buffer_label.set_mnemonic_widget(scale)

        def rebuild_pipeline(*args):
            player._rebuild_pipeline()
        apply_button.connect('clicked', rebuild_pipeline)

        gapless_button = ConfigCheckButton(
            _('Disable _gapless playback'),
            "player", "gst_disable_gapless", populate=True)
        gapless_button.set_alignment(0.0, 0.5)
        gapless_button.set_tooltip_text(
            _("Disabling gapless playback can avoid track changing problems "
              "with some GStreamer versions."))

        widgets = [(pipe_label, e, apply_button),
                   (buffer_label, scale, None),
        ]

        table = Gtk.Table(n_rows=len(widgets), n_columns=3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        for i, (left, middle, right) in enumerate(widgets):
            left.set_alignment(0.0, 0.5)
            table.attach(left, 0, 1, i, i + 1,
                         xoptions=Gtk.AttachOptions.FILL |
                         Gtk.AttachOptions.SHRINK)
            if right:
                table.attach(middle, 1, 2, i, i + 1)
                table.attach(right, 2, 3, i, i + 1,
                             xoptions=Gtk.AttachOptions.FILL |
                             Gtk.AttachOptions.SHRINK)
            else:
                table.attach(middle, 1, 3, i, i + 1)

        table.attach(gapless_button, 0, 3, 2, 3)

        self.pack_start(table, True, True, 0)

        if debug:
            def print_bin(player):
                player._print_pipeline()

            b = Button("Print Pipeline", Gtk.STOCK_DIALOG_INFO)
            connect_obj(b, 'clicked', print_bin, player)
            self.pack_start(b, True, True, 0)
Example #55
0
    def __init__(self, player, debug=False):
        super().__init__(spacing=6)

        e = UndoEntry()
        e.set_tooltip_text(
            _("The GStreamer output pipeline used for "
              "playback. Leave blank for the default pipeline. "
              "In case the pipeline contains a sink, "
              "it will be used instead of the default one."))

        e.set_text(config.get('player', 'gst_pipeline'))

        def changed(entry):
            config.set('player', 'gst_pipeline', entry.get_text())

        e.connect('changed', changed)

        pipe_label = Gtk.Label(label=_('_Output pipeline:'))
        pipe_label.set_use_underline(True)
        pipe_label.set_mnemonic_widget(e)

        apply_button = Button(_("_Apply"))

        def format_buffer(scale, value):
            return _("%.1f seconds") % value

        def scale_changed(scale):
            duration_msec = int(scale.get_value() * 1000)
            player._set_buffer_duration(duration_msec)

        duration = config.getfloat("player", "gst_buffer")
        scale = Gtk.HScale.new(
            Gtk.Adjustment(value=duration, lower=0.2, upper=10))
        scale.set_value_pos(Gtk.PositionType.RIGHT)
        scale.set_show_fill_level(True)
        scale.connect('format-value', format_buffer)
        scale.connect('value-changed', scale_changed)

        buffer_label = Gtk.Label(label=_('_Buffer duration:'))
        buffer_label.set_use_underline(True)
        buffer_label.set_mnemonic_widget(scale)

        def rebuild_pipeline(*args):
            player._rebuild_pipeline()

        apply_button.connect('clicked', rebuild_pipeline)

        gapless_button = ConfigCheckButton(
            _('Disable _gapless playback'),
            "player",
            "gst_disable_gapless",
            populate=True,
            tooltip=_(
                "Disabling gapless playback can avoid track changing problems "
                "with some GStreamer versions"))

        jack_button = ConfigCheckButton(
            _('Use JACK for playback if available'),
            "player",
            "gst_use_jack",
            populate=True,
            tooltip=_(
                "Uses `jackaudiosink` for playbin sink if it can be detected"))
        jack_connect = ConfigCheckButton(
            _('Auto-connect to JACK output devices'),
            "player",
            "gst_jack_auto_connect",
            populate=True,
            tooltip=_("Tells `jackaudiosink` to auto-connect"))

        def _jack_toggled(widget: ConfigCheckButton) -> None:
            jack_connect.set_sensitive(widget.get_active())

        jack_button.connect("clicked", _jack_toggled)
        _jack_toggled(jack_button)
        widgets = [(pipe_label, e, apply_button), (buffer_label, scale, None)]

        table = Gtk.Table(n_rows=len(widgets) + 3, n_columns=3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        for i, (left, middle, right) in enumerate(widgets):
            left.set_alignment(0.0, 0.5)
            table.attach(left,
                         0,
                         1,
                         i,
                         i + 1,
                         xoptions=Gtk.AttachOptions.FILL
                         | Gtk.AttachOptions.SHRINK)
            if right:
                table.attach(middle, 1, 2, i, i + 1)
                table.attach(right,
                             2,
                             3,
                             i,
                             i + 1,
                             xoptions=Gtk.AttachOptions.FILL
                             | Gtk.AttachOptions.SHRINK)
            else:
                table.attach(middle, 1, 3, i, i + 1)

        table.attach(gapless_button, 0, 3, 2, 3)
        table.attach(jack_button, 0, 3, 3, 4)
        table.attach(jack_connect, 0, 3, 4, 5)

        self.pack_start(table, True, True, 0)

        if debug:

            def print_bin(player):
                player._print_pipeline()

            b = Button("Print Pipeline", Icons.DIALOG_INFORMATION)
            connect_obj(b, 'clicked', print_bin, player)
            self.pack_start(b, True, True, 0)
Example #56
0
        def ratings_vbox(self):
            """Returns a new VBox containing all ratings widgets"""
            vb = Gtk.VBox(spacing=6)

            # Default Rating
            model = Gtk.ListStore(float)
            default_combo = Gtk.ComboBox(model=model)
            default_lab = Gtk.Label(label=_("_Default rating:"))
            default_lab.set_use_underline(True)
            default_lab.set_alignment(0, 0.5)

            def draw_rating(column, cell, model, it, data):
                num = model[it][0]
                text = "%0.2f: %s" % (num, util.format_rating(num))
                cell.set_property('text', text)

            def default_rating_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.default = model[it][0]

            def populate_default_rating_model(combo, num):
                model = combo.get_model()
                model.clear()
                deltas = []
                default = RATINGS.default
                precision = RATINGS.precision
                for i in range(0, num + 1):
                    r = i * precision
                    model.append(row=[r])
                    deltas.append((abs(default - r), i))
                active = sorted(deltas)[0][1]
                print_d("Choosing #%d (%.2f), closest to current %.2f"
                        % (active, precision * active, default))
                combo.set_active(active)

            cell = Gtk.CellRendererText()
            default_combo.pack_start(cell, True)
            default_combo.set_cell_data_func(cell, draw_rating, None)
            default_combo.connect('changed', default_rating_changed, model)
            default_lab.set_mnemonic_widget(default_combo)

            def refresh_default_combo(num):
                populate_default_rating_model(default_combo, num)

            # Rating Scale
            model = Gtk.ListStore(int)
            scale_combo = Gtk.ComboBox(model=model)
            scale_lab = Gtk.Label(label=_("Rating _Scale:"))
            scale_lab.set_use_underline(True)
            scale_lab.set_mnemonic_widget(scale_combo)

            cell = Gtk.CellRendererText()
            scale_combo.pack_start(cell, False)
            num = RATINGS.number
            for i in [1, 2, 3, 4, 5, 6, 8, 10]:
                it = model.append(row=[i])
                if i == num:
                    scale_combo.set_active_iter(it)

            def draw_rating_scale(column, cell, model, it, data):
                num_stars = model[it][0]
                text = "%d: %s" % (num_stars, RATINGS.full_symbol * num_stars)
                cell.set_property('text', text)

            def rating_scale_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.number = num = model[it][0]
                refresh_default_combo(num)

            refresh_default_combo(RATINGS.number)
            scale_combo.set_cell_data_func(cell, draw_rating_scale, None)
            scale_combo.connect('changed', rating_scale_changed, model)

            default_align = Gtk.Alignment(xalign=0, xscale=0)
            default_align.add(default_lab)
            default_combo_align = Gtk.Alignment(xalign=0, xscale=0)
            default_combo_align.add(default_combo)
            scale_align = Gtk.Alignment(xalign=0, xscale=0)
            scale_align.add(scale_lab)

            grid = Gtk.Grid(column_spacing=6, row_spacing=6)
            grid.add(scale_align)
            grid.add(scale_combo)
            grid.attach(default_align, 0, 1, 1, 1)
            grid.attach(default_combo_align, 1, 1, 1, 1)
            vb.pack_start(grid, False, False, 6)

            # Bayesian Factor
            bayesian_factor = config.getfloat("settings",
                                              "bayesian_rating_factor", 0.0)
            adj = Gtk.Adjustment.new(bayesian_factor, 0.0, 10.0, 0.5, 0.5, 0.0)
            bayes_spin = Gtk.SpinButton(adjustment=adj, numeric=True)
            bayes_spin.set_digits(1)
            bayes_spin.connect('changed', self.__changed_and_signal_library,
                               'settings', 'bayesian_rating_factor')
            bayes_spin.set_tooltip_text(
                _("Bayesian Average factor (C) for aggregated ratings.\n"
                  "0 means a conventional average, higher values mean that "
                  "albums with few tracks will have less extreme ratings. "
                  "Changing this value triggers a re-calculation for all "
                  "albums."))
            bayes_label = Gtk.Label(label=_("_Bayesian averaging amount:"))
            bayes_label.set_use_underline(True)
            bayes_label.set_mnemonic_widget(bayes_spin)

            # Save Ratings
            hb = Gtk.HBox(spacing=6)
            hb.pack_start(bayes_label, False, True, 0)
            hb.pack_start(bayes_spin, False, True, 0)
            vb.pack_start(hb, True, True, 0)
            cb = CCB(_("Save ratings and play _counts"),
                     "editing", "save_to_songs", populate=True)
            vb.pack_start(cb, True, True, 0)
            hb = Gtk.HBox(spacing=6)
            lab = Gtk.Label(label=_("_Email:"))
            entry = UndoEntry()
            entry.set_tooltip_text(_("Ratings and play counts will be set "
                                     "for this email address"))
            entry.set_text(config.get("editing", "save_email"))
            entry.connect('changed', self.__changed, 'editing', 'save_email')
            hb.pack_start(lab, False, True, 0)
            hb.pack_start(entry, True, True, 0)
            lab.set_mnemonic_widget(entry)
            lab.set_use_underline(True)
            vb.pack_start(hb, True, True, 0)

            return vb
Example #57
0
        def __init__(self):
            super(PreferencesWindow.Player, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Playback")

            # player backend
            if app.player and hasattr(app.player, 'PlayerPreferences'):
                player_prefs = app.player.PlayerPreferences()
                f = qltk.Frame(_("Output Configuration"), child=player_prefs)
                self.pack_start(f, False, True, 0)

            # replaygain
            fallback_gain = config.getfloat("player", "fallback_gain", 0.0)
            adj = Gtk.Adjustment.new(fallback_gain, -12.0, 12.0, 0.5, 0.5, 0.0)
            fb_spin = Gtk.SpinButton(adjustment=adj)
            fb_spin.set_digits(1)
            fb_spin.connect('changed', self.__changed,
                            'player', 'fallback_gain')
            fb_spin.set_tooltip_text(
                _("If no Replay Gain information is available "
                  "for a song, scale the volume by this value"))

            fb_label = Gtk.Label(label=_("_Fall-back gain (dB):"))
            fb_label.set_use_underline(True)
            fb_label.set_mnemonic_widget(fb_spin)

            pre_amp_gain = config.getfloat("player", "pre_amp_gain", 0.0)
            adj = Gtk.Adjustment.new(pre_amp_gain, -6, 6, 0.5, 0.5, 0.0)
            adj.connect('value-changed', self.__changed,
                        'player', 'pre_amp_gain')
            pre_spin = Gtk.SpinButton(adjustment=adj)
            pre_spin.set_digits(1)
            pre_spin.set_tooltip_text(
                _("Scale volume for all songs by this value, "
                  "as long as the result will not clip"))

            pre_label = Gtk.Label(label=_("_Pre-amp gain (dB):"))
            pre_label.set_use_underline(True)
            pre_label.set_mnemonic_widget(pre_spin)

            widgets = [pre_label, pre_spin, fb_label, fb_spin]
            c = CCB(_("_Enable Replay Gain volume adjustment"),
                    "player", "replaygain", populate=True)
            c.connect('toggled', self.__toggled_gain, widgets)

            # packing
            table = Gtk.Table.new(3, 2, False)
            table.set_col_spacings(6)
            table.set_row_spacings(6)

            table.attach(c, 0, 2, 0, 1)
            fb_label.set_alignment(0, 0.5)
            table.attach(fb_label, 0, 1, 1, 2,
                         xoptions=0)
            pre_label.set_alignment(0, 0.5)
            table.attach(pre_label, 0, 1, 2, 3,
                         xoptions=0)

            fb_align = Gtk.Alignment.new(0, 0.5, 0, 1)
            fb_align.add(fb_spin)
            table.attach(fb_align, 1, 2, 1, 2)

            pre_align = Gtk.Alignment.new(0, 0.5, 0, 1)
            pre_align.add(pre_spin)
            table.attach(pre_align, 1, 2, 2, 3)

            f = qltk.Frame(_("Replay Gain Volume Adjustment"), child=table)

            c.emit('toggled')

            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Example #58
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Cover Grid Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)
        self.mag_lock = False

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(
            _("Show album _text"), "browsers", "album_text")
        cb.set_active(config.getboolean("browsers", "album_text"))
        cb.connect('toggled',
                   lambda s: browser.toggle_text())
        vbox.pack_start(cb, False, True, 0)

        cb2 = ConfigCheckButton(
            _("Show \"All Albums\" Item"), "browsers", "covergrid_all")
        cb2.set_active(config.getboolean("browsers", "covergrid_all", False))
        cb2.connect('toggled',
                   lambda s: browser.view.get_model().refilter())
        vbox.pack_start(cb2, False, True, 0)

        cb3 = ConfigCheckButton(
            _("Wide Mode"), "browsers", "covergrid_wide")
        cb3.set_active(config.getboolean("browsers",
            "covergrid_wide", False))
        cb3.connect('toggled',
                   lambda s: browser.toggle_wide())
        vbox.pack_start(cb3, False, True, 0)

        # Redraws the covers only when the user releases the slider
        def mag_button_press(*_):
            self.mag_lock = True

        def mag_button_release(mag, _):
            self.mag_lock = False
            mag_changed(mag)

        def mag_changed(mag):
            if self.mag_lock:
                return
            newmag = mag.get_value()
            oldmag = config.getfloat("browsers", "covergrid_magnification", 3.)
            if newmag == oldmag:
                print_d("Covergrid magnification haven't changed: {0}"
                        .format(newmag))
                return
            print_d('Covergrid magnification update from {0} to {1}'
                    .format(oldmag, newmag))
            config.set("browsers", "covergrid_magnification", mag.get_value())
            browser.update_mag()

        mag_scale = Gtk.HScale(
            adjustment=Gtk.Adjustment.new(config.getfloat("browsers",
                "covergrid_magnification", 3), 0., 10., .5, .5, 0))
        mag_scale.set_tooltip_text(_("Cover Magnification"))
        l = Gtk.Label(label=_("Cover Magnification"))
        mag_scale.set_value_pos(Gtk.PositionType.RIGHT)
        mag_scale.connect('button-press-event', mag_button_press)
        mag_scale.connect('button-release-event', mag_button_release)
        mag_scale.connect('value-changed', mag_changed)

        vbox.pack_start(l, False, True, 0)
        vbox.pack_start(mag_scale, False, True, 0)

        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Example #59
0
 def on_reverted(*args):
     config.reset(section, option)
     scale.set_value(config.getfloat(section, option))