[proaudio] [1773] media-sound/boodler-2.0.3-r1 add docs, pyqt4 gui, ~amd64 kw, misc fixes. |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/proaudio Archives
]
Revision: 1773
Author: gavlee
Date: 2010-10-22 07:26:34 +0200 (Fri, 22 Oct 2010)
Log Message:
-----------
media-sound/boodler-2.0.3-r1 add docs, pyqt4 gui, ~amd64 kw, misc fixes.
Modified Paths:
--------------
trunk/overlays/proaudio/media-sound/boodler/ChangeLog
trunk/overlays/proaudio/media-sound/boodler/Manifest
Added Paths:
-----------
trunk/overlays/proaudio/media-sound/boodler/boodler-2.0.3-r1.ebuild
trunk/overlays/proaudio/media-sound/boodler/files/boodle-ui-qt.py
Modified: trunk/overlays/proaudio/media-sound/boodler/ChangeLog
===================================================================
--- trunk/overlays/proaudio/media-sound/boodler/ChangeLog 2010-10-21 19:43:03 UTC (rev 1772)
+++ trunk/overlays/proaudio/media-sound/boodler/ChangeLog 2010-10-22 05:26:34 UTC (rev 1773)
@@ -2,6 +2,14 @@
# Copyright 1999-2010 Gentoo Foundation; Distributed under the GPL v2
# $Header: $
+*boodler-2.0.3-r1 (22 Oct 2010)
+
+ 22 Oct 2010; Gavin Pryke <gavinlee303@xxxxxxxxxxxxxx>
+ +boodler-2.0.3-r1.ebuild, +files/boodle-ui-qt.py:
+ add ~amd64 keyword. add coreaudio and doc USE flags. include a pyqt4 gui with
+ USE=qt4. work around selection of default audio driver. remove python inherit
+ as distutils is already inherited.
+
*boodler-2.0.3 (15 Oct 2010)
15 Oct 2010; Gavin Pryke <gavinlee303@xxxxxxxxxxxxxx>
Modified: trunk/overlays/proaudio/media-sound/boodler/Manifest
===================================================================
--- trunk/overlays/proaudio/media-sound/boodler/Manifest 2010-10-21 19:43:03 UTC (rev 1772)
+++ trunk/overlays/proaudio/media-sound/boodler/Manifest 2010-10-22 05:26:34 UTC (rev 1773)
@@ -1,3 +1,4 @@
+AUX boodle-ui-qt.py 12114 RMD160 b233bfcd8a51b129dd0d2466f08b126a41077894 SHA1 bf8402a5ce0480f93bdc9ac1bb6596adab8a3db7 SHA256 b2a0ea4dc175e7e175671bfca48bafe44a0bd37801babcd7e23e492ad34130a4
AUX boodler 2156 RMD160 3f14fe314d6d4f3dc05d566a710a9348825eb358 SHA1 5442b4abfc45054f7395afa16e1b359704bccf5e SHA256 b2f5fbc14dc152e78fdaca0b23020a8df03956c1987ce379df8cf082937177a1
DIST Boodler-2.0.2.tar.gz 303617 RMD160 2d0577027bfb6cfb295e6d1eaf54fb3dcea4a56b SHA1 a153f58b3b39763a7876bbd28632a05134bbf522 SHA256 94a687d4ce854fc0d7749da6953d0f17efbcd00ad30359299f4d478f6b8e5197
DIST Boodler-2.0.3.tar.gz 306478 RMD160 3499e5894a7fe457b3aafaaadebbc1063223e019 SHA1 1f543d4a09930fe33e680f1d6cf986abf07fd29e SHA256 fe432e35737aa14e3595930df05f85ecd24ba0278365c34c4028192c20a06088
@@ -2,4 +3,5 @@
EBUILD boodler-2.0.2.ebuild 1647 RMD160 597802fd10303055a77bf1f2cb0ed7fd48504b02 SHA1 fbef618c802ec9323a8e72bf87487727e348bc09 SHA256 521d5270b7bdadd73849d3e29d9e2036cd58b43d4d7b984c364bd9d148eab5d5
+EBUILD boodler-2.0.3-r1.ebuild 3507 RMD160 44fdfbf5e6dc4303f03443d59f68c3574001cf51 SHA1 5876d4c9ee9debdc810fa7b0c0cdeb5749723411 SHA256 70c8cb81be0d68f4a658b5c442fe592abcdfc247bf05395ebca421082b6b2ae1
EBUILD boodler-2.0.3.ebuild 1977 RMD160 78d123848f328faebffd460abbf34a4839383e5c SHA1 1ac8e96111be945a46507a7cebe5ac533440929e SHA256 ab3ce6546a7a1e54eff9eacee8bf5dd6b182dfe8313742676e42aa3cc285ddd3
-MISC ChangeLog 556 RMD160 6119fd0b97141353903a4fa720226507a88c624f SHA1 9c805e3ee3b52def6ac01d079fdbea7c17da2b36 SHA256 ac4502e83ed91585f5f5615125d970c978c3b590b5b4b41071eeaf8545db25f5
+MISC ChangeLog 895 RMD160 238c949be565723daf7d33ec156352ff60f507f0 SHA1 f3ceac163b6a4c4610bf4a52adab369e1cc6f6ff SHA256 453fcc1a0f4a8530d97a13b9c5748a18f314722d8aeb42a19f42c654d57705bd
MISC metadata.xml 457 RMD160 035f8f3790a1a312b132650bca012e2db915a57d SHA1 2098a41f73f85e1b3e75e10cb494117df2cb7587 SHA256 723b7bd3d0f84f5193ad64b625597ba2f9dc5c7d250a8b636b8cada6ad5f682b
Added: trunk/overlays/proaudio/media-sound/boodler/boodler-2.0.3-r1.ebuild
===================================================================
--- trunk/overlays/proaudio/media-sound/boodler/boodler-2.0.3-r1.ebuild (rev 0)
+++ trunk/overlays/proaudio/media-sound/boodler/boodler-2.0.3-r1.ebuild 2010-10-22 05:26:34 UTC (rev 1773)
@@ -0,0 +1,117 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI=2
+
+PYTHON_DEPEND="2:2.4"
+
+inherit distutils bash-completion
+
+MY_P="Boodler-${PV}"
+
+DESCRIPTION="Tool for creating soundscapes -- continuous, infinitely varying streams of sound"
+HOMEPAGE="http://boodler.org/"
+SRC_URI="http://boodler.org/dl/${MY_P}.tar.gz"
+LICENSE="LGPL-2 GPL-2 public-domain"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE="alsa bash-completion coreaudio doc esd intmath jack lame pulseaudio qt4 shout vorbis"
+
+RESTRICT="mirror"
+
+DEPEND="alsa? ( >=media-libs/alsa-lib-1.0.17a )
+ esd? ( >=media-sound/esound-0.2.41 )
+ jack? ( >=media-libs/bio2jack-0.9 )
+ lame? ( >=media-sound/lame-3.98.2-r1 )
+ pulseaudio? ( >=media-sound/pulseaudio-0.9.9 )
+ shout? ( >=media-libs/libshout-2.1 )
+ vorbis? ( >=media-libs/libvorbis-1.2.1_rc1-r2 )"
+RDEPEND="${DEPEND}
+ qt4? ( >=dev-python/PyQt4-4.7.3[X] )"
+
+S="${WORKDIR}/${MY_P}"
+
+pkg_setup() {
+ if use shout && ! use vorbis ; then
+ eerror "To have shout support, you also need to build boodler with"
+ eerror "USE=\"vorbis\"!"
+ die
+ fi
+}
+
+src_prepare() {
+ local defdriver
+ local with
+ local without
+
+ # set up a default audio driver (not daemon) according to USE flags.
+ # it does not appear to work in setup.cfg so there is a workaround below.
+ if use coreaudio ; then
+ defdriver=macosx
+ elif use alsa ; then
+ defdriver=alsa
+ else
+ defdriver=oss
+ fi
+
+ # this ugly code enables/disables the output drivers
+ # oss seems to be needed for boodler.py --list-drivers to work
+ with="${with}oss,"
+ use alsa && with="${with}alsa," || without="${without}alsa,"
+ use coreaudio && with="${with}macosx,osxaq," \
+ || without="${without}macosx,osxaq,"
+ use esd && with="${with}esd," || without="${without}esd,"
+ use jack && with="${with}jackb," || without="${without}jackb,"
+ use lame && with="${with}lame," || without="${without}lame,"
+ use pulseaudio && with="${with}pulse," || without="${without}pulse,"
+ use shout && with="${with}shout," || without="${without}shout,"
+ use vorbis && with="${with}vorbis," || without="${without}vorbis,"
+
+ # move the original setup.cfg out of the way as a backup to check syntax
+ mv "${S}/setup.cfg" "${T}/setup.cfg.original" || die "setup.cfg not found"
+
+ # fill the setup.cfg with the values
+ cat > "${S}/setup.cfg" <<-EOF
+ [build_scripts]
+ default_driver=${defdriver}
+ [build_ext]
+ with-drivers=${with}
+ without-drivers=${without}
+ intmath=$(use intmath && echo 1 || echo 0)
+ EOF
+
+ # workaround for default-driver in setup.cfg not functioning
+ $(PYTHON) setup.py build_scripts \
+ --default-driver ${defdriver} \
+ || die "$(PYTHON) setup.py build_scripts failed"
+
+ # fix boodle-ui-qt.py shebang
+ if use qt4 ; then
+ cp "${FILESDIR}/boodle-ui-qt.py" "${T}/boodle-ui-qt.py" \
+ || die "cp ${FILESDIR}/boodle-ui-qt.py ${T}/boodle-ui-qt.py failed"
+ python_convert_shebangs $(python_get_version) "${T}/boodle-ui-qt.py"
+ fi
+}
+
+src_install() {
+ distutils_src_install
+
+ # a bash completion addon script downloaded from the official site
+ # http://boodler.org/dl/etc/bash_completion.d/boodler
+ dobashcompletion "${FILESDIR}/boodler"
+
+ # a pyqt4 gui addon for boodler downloaded from the official site
+ # http://boodler.org/dl/etc/boodle-ui-qt.py
+ if use qt4 ; then
+ dobin "${T}/boodle-ui-qt.py" || die "boodle-ui-qt.py not found"
+ fi
+
+ # docs, better include them as boodler is not the most intuitive to use for
+ # new users
+ if use doc ; then
+ pushd doc || die "doc dir not found"
+ dohtml -r *
+ popd
+ fi
+}
Added: trunk/overlays/proaudio/media-sound/boodler/files/boodle-ui-qt.py
===================================================================
--- trunk/overlays/proaudio/media-sound/boodler/files/boodle-ui-qt.py (rev 0)
+++ trunk/overlays/proaudio/media-sound/boodler/files/boodle-ui-qt.py 2010-10-22 05:26:34 UTC (rev 1773)
@@ -0,0 +1,316 @@
+#!/usr/bin/python
+
+# Boodler: a programmable soundscape tool
+# Designed by Andrew Plotkin <erkyrath@xxxxxxxxxx>
+# For more information, see <http://boodler.org/>
+#
+# This Python script ("boodle-ui-qt.py") is licensed under the GNU
+# Library General Public License (LGPL).
+# Author: Tuukka Hastrup <Tuukka.Hastrup@xxxxxx>
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this program. (It should be a document entitled "LGPL".)
+# If not, see the web URL above, or write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import sys
+import subprocess
+import os, signal
+
+from boopak import collect # you'll need Boodler on Python's library path
+
+# same as in boodler.py
+if 'darwin' in sys.platform.lower():
+ Default_Relative_Data_Dir = 'Library/Application Support/Boodler'
+else:
+ Default_Relative_Data_Dir = '.boodler'
+
+basedir = None # XXX opts.basedir
+if not basedir:
+ basedir = os.environ.get('BOODLER_DATA')
+if not basedir:
+ basedir = os.path.join(os.environ.get('HOME'), Default_Relative_Data_Dir)
+
+
+# collect the list of agents
+
+l = collect.PackageCollection(basedir=basedir)
+
+pkgs = l.list_all_current_packages()
+
+agents = []
+
+for pkgname,_vers in sorted(pkgs):
+ pkg = l.load(pkgname)
+ for resname in sorted(pkg.resources.keys()):
+ res = pkg.resources.get(resname)
+ if res.get_one("boodler.use") == "agent":
+ agents += [(pkgname, resname)]
+
+
+def play(agent):
+ boodler = ["boodler.py", "%s/%s" % agent]
+ return boodler
+
+def textplay(agent):
+ print "Playing %s/%s" % agent,
+
+ pkg = l.load(agent[0])
+ res = pkg.resources.get(agent[1])
+ print '"%s"' % res.get_one("dc.title"), "... ",
+
+ sys.stdout.flush()
+
+ boodler = subprocess.Popen(play(agent), stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ try:
+ boodler.communicate()
+ if boodler.returncode == 0:
+ print "Done."
+ else:
+ print "Boodler failed with exit code %s." % boodler.returncode
+ except KeyboardInterrupt:
+ print "\nInterrupted"
+ os.kill(boodler.pid, signal.SIGTERM)
+ try:
+ boodler.wait()
+ except KeyboardInterrupt:
+ os.kill(boodler.pid, signal.SIGKILL)
+
+def textmain():
+ for agent in agents:
+ textplay(agent)
+
+def qtmain():
+ from PyQt4 import QtCore, QtGui # you'll need PyQt4 (python-qt4)
+
+ def index2rowdata(index):
+ rowdata = (index.sibling(index.row(), 0).data().toString(),
+ index.sibling(index.row(), 1).data().toString(),
+ index.sibling(index.row(), 2).data().toString(),
+ )
+
+ return rowdata
+
+ class Window(QtGui.QWidget):
+ def __init__(self, app):
+ self.boodler = None
+
+ QtGui.QWidget.__init__(self)
+
+ self.connect(app, QtCore.SIGNAL('aboutToQuit()'), self.stopPlay)
+
+ # proxy model for sorting and filtering
+ self.proxyModel = QtGui.QSortFilterProxyModel()
+ self.proxyModel.setDynamicSortFilter(True)
+ self.proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
+ self.proxyModel.setFilterKeyColumn(2)
+
+ # widgets for now playing agent
+ self.nowPlayingGroupBox = QtGui.QGroupBox("Now playing")
+ self.nowPlayingLabel = QtGui.QLabel("Double-click a soundscape to play\n")
+ self.nowPlayingButton = QtGui.QPushButton(self.style().standardIcon(QtGui.QStyle.SP_MediaStop), "&Stop")
+ self.nowPlayingButton.setEnabled(False)
+
+ # signals for now playing agent
+ self.connect(self.nowPlayingButton, QtCore.SIGNAL('clicked()'), self.stopPlay)
+
+ # widgets for selected agent
+ self.selectedGroupBox = QtGui.QGroupBox("Selected soundscape")
+ self.selectedLabel = QtGui.QLabel("Click a soundscape to view details\n")
+ self.selectedInfoLabel = QtGui.QLabel("Internal name:\nLicense:\nSource:")
+ self.selectedButton = QtGui.QPushButton(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay), "&Play")
+ self.selectedButton.setEnabled(False)
+
+ # signals for now playing agent
+ self.connect(self.selectedButton, QtCore.SIGNAL('clicked()'), self.playButtonClicked)
+
+ # view widgets
+ self.proxyGroupBox = QtGui.QGroupBox("Available soundscapes")
+
+ self.proxyView = QtGui.QTreeView()
+ self.proxyView.setRootIsDecorated(False)
+ self.proxyView.setAlternatingRowColors(True)
+ self.proxyView.setModel(self.proxyModel)
+ self.proxyView.setSortingEnabled(True)
+ self.proxyView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
+ self.proxyView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
+ self.proxyView.setAllColumnsShowFocus(True)
+
+ # filter pattern widgets
+ self.filterPatternLineEdit = QtGui.QLineEdit()
+ self.filterPatternLabel = QtGui.QLabel("F&ind:")
+ self.filterPatternLabel.setBuddy(self.filterPatternLineEdit)
+
+ # filter pattern signals
+ self.connect(self.filterPatternLineEdit,
+ QtCore.SIGNAL('textChanged(const QString &)'),
+ self.filterRegExpChanged)
+
+ self.connect(self.proxyView.selectionModel(),
+ QtCore.SIGNAL('currentRowChanged(const QModelIndex &, const QModelIndex &)'),
+ self.itemSelected)
+ self.connect(self.proxyView, QtCore.SIGNAL('activated(const QModelIndex &)'), self.itemActivated)
+
+ # now playing layout
+ nowPlayingLayout = QtGui.QHBoxLayout()
+ nowPlayingLayout.addWidget(self.nowPlayingButton)
+ nowPlayingLayout.addWidget(self.nowPlayingLabel, 1)
+ self.nowPlayingGroupBox.setLayout(nowPlayingLayout)
+
+ # selected layout
+ selectedLayout = QtGui.QVBoxLayout()
+ selectedLayoutH = QtGui.QHBoxLayout()
+ selectedLayoutH.addWidget(self.selectedButton)
+ selectedLayoutH.addWidget(self.selectedLabel, 1)
+ selectedLayout.addLayout(selectedLayoutH)
+ selectedLayout.addWidget(self.selectedInfoLabel)
+ self.selectedGroupBox.setLayout(selectedLayout)
+
+ # available agents layout
+ filterPatternLayout = QtGui.QHBoxLayout()
+ filterPatternLayout.addWidget(self.filterPatternLabel)
+ filterPatternLayout.addWidget(self.filterPatternLineEdit)
+
+ proxyLayout = QtGui.QVBoxLayout()
+ proxyLayout.addWidget(self.proxyView)
+ proxyLayout.addLayout(filterPatternLayout)
+ self.proxyGroupBox.setLayout(proxyLayout)
+
+ # main layout
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(self.nowPlayingGroupBox)
+ mainLayout.addWidget(self.selectedGroupBox)
+ mainLayout.addWidget(self.proxyGroupBox)
+ self.setLayout(mainLayout)
+
+ # set top-level window properties
+ self.setWindowTitle("Boodle UI")
+ self.resize(500, 450)
+
+ # set initial state
+ self.proxyView.sortByColumn(2, QtCore.Qt.AscendingOrder)
+ self.filterPatternLineEdit.setText("")
+
+ def setSourceModel(self, model):
+ self.proxyModel.setSourceModel(model)
+
+ def filterRegExpChanged(self):
+ regExp = QtCore.QRegExp(self.filterPatternLineEdit.text(), QtCore.Qt.CaseInsensitive, QtCore.QRegExp.Wildcard)
+ self.proxyModel.setFilterRegExp(regExp)
+
+ def itemSelected(self, currentIndex, _previousIndex):
+ if not currentIndex.isValid():
+ return # keep the latest selection, if any
+ row = index2rowdata(currentIndex)
+ self.lastSelectedRow = row
+ self.selectedButton.setEnabled(True)
+ self.updateSelected(row)
+
+ def itemActivated(self, index):
+ row = index2rowdata(index)
+ self.startPlay((str(row[0]), str(row[1])))
+ self.updateNowPlaying(row)
+
+ def playButtonClicked(self):
+ row = self.lastSelectedRow
+ self.startPlay((str(row[0]), str(row[1])))
+ self.updateNowPlaying(row)
+
+ def updateNowPlaying(self, row):
+ pkg = l.load(str(row[0]))
+ creator = pkg.metadata.get_one("dc.creator")
+ pkgtitle = pkg.metadata.get_one("dc.title")
+
+ msg = '"%s"\nby %s from "%s"' % (row[2], creator, pkgtitle)
+ self.nowPlayingLabel.setText(msg)
+
+ def updateSelected(self, row):
+ pkg = l.load(str(row[0]))
+ creator = pkg.metadata.get_one("dc.creator")
+ pkgtitle = pkg.metadata.get_one("dc.title")
+ license = pkg.metadata.get_one("dc.license")
+ source = pkg.metadata.get_one("dc.source")
+
+ msg = '"%s"\nby %s from "%s"' % (row[2], creator, pkgtitle)
+ self.selectedLabel.setText(msg)
+
+ info = 'Internal name: %s/%s' % (row[0], row[1])
+ info += '\nLicense: %s' % license
+ info += '\nSource: %s' % source
+ self.selectedInfoLabel.setText(info)
+
+ def startPlay(self, agent):
+ self.stopPlay()
+
+ self.boodler = QtCore.QProcess(self)
+ self.connect(self.boodler, QtCore.SIGNAL('error(QProcess::ProcessError)'), self.playError)
+ self.connect(self.boodler, QtCore.SIGNAL('finished(int,QProcess::ExitStatus)'), self.playFinished)
+
+ cmd = play(agent)
+ print "Launching: %s" % ' '.join(cmd)
+ self.boodler.start(cmd[0], cmd[1:])
+
+ self.nowPlayingButton.setEnabled(True)
+
+ def stopPlay(self):
+ if self.boodler:
+ self.disconnect(self.boodler, QtCore.SIGNAL('error(QProcess::ProcessError)'), self.playError)
+ self.disconnect(self.boodler, QtCore.SIGNAL('finished(int, QProcess::ExitStatus)'), self.playFinished)
+ if self.boodler.state() != QtCore.QProcess.NotRunning:
+ self.boodler.terminate()
+ if not self.boodler.waitForFinished(5000):
+ self.boodler.kill()
+ self.boodler = None
+
+ self.nowPlayingButton.setEnabled(False)
+
+ def playError(self, error):
+ if error == QtCore.QProcess.FailedToStart:
+ print "Boodler failed to start: %s" % self.boodler.errorString()
+ elif error == QtCore.QProcess.Crashed:
+ print "Boodler crashed with exit code %s." % self.boodler.exitCode()
+ else:
+ print "Boodler failed with error %s." % error
+
+ self.stopPlay()
+
+ def playFinished(self, exitCode, exitStatus):
+ if exitCode != 0:
+ print self.boodler.readAllStandardError()
+ print "Boodler failed with exit code %s." % exitCode
+ else:
+ print "Boodler done playing."
+
+ self.stopPlay()
+
+ def createAgentModel(parent):
+ model = QtGui.QStandardItemModel(0, 3, parent)
+
+ model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Package"))
+ model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Resource"))
+ model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Title"))
+
+ def standardItem(x):
+ if x is None:
+ return QtGui.QStandardItem("")
+ else:
+ return QtGui.QStandardItem(x)
+
+ for agent in reversed(agents):
+ pkg = l.load(agent[0])
+ res = pkg.resources.get(agent[1])
+ title = res.get_one("dc.title")
+ model.appendRow(map(standardItem, [agent[0], agent[1], title]))
+
+ return model
+
+ app = QtGui.QApplication(sys.argv)
+ window = Window(app)
+ window.setSourceModel(createAgentModel(window))
+ window.show()
+ sys.exit(app.exec_())
+
+
+qtmain()