Merged my unitary FFT wrappers (FFT_tools) as hooke.util.fft.
[hooke.git] / hooke / plugin / playlist.py
1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
2 #
3 # This file is part of Hooke.
4 #
5 # Hooke is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation, either
8 # version 3 of the License, or (at your option) any later version.
9 #
10 # Hooke is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke.  If not, see
17 # <http://www.gnu.org/licenses/>.
18
19 """The ``playlist`` module provides :class:`PlaylistPlugin` and
20 several associated :class:`hooke.command.Command`\s for handling
21 :mod:`hooke.playlist` classes.
22 """
23
24 import glob
25
26 from ..command import Command, Argument, Failure
27 from ..playlist import FilePlaylist
28 from ..plugin import Builtin
29
30
31 class PlaylistPlugin (Builtin):
32     def __init__(self):
33         super(PlaylistPlugin, self).__init__(name='playlist')
34
35     def commands(self):
36         return [NextCommand(), PreviousCommand(), JumpCommand(),
37                 IndexCommand(), CurveListCommand(),
38                 SaveCommand(), LoadCommand(),
39                 AddCommand(), AddGlobCommand(),
40                 RemoveCommand(), FilterCommand(), NoteFilterCommand()]
41
42
43 # Define common or complicated arguments
44
45 def current_playlist_callback(hooke, command, argument, value):
46     if value != None:
47         return value
48     playlist = hooke.playlists.current()
49     if playlist == None:
50         raise Failure('No playlists loaded')
51     return playlist
52
53 PlaylistArgument = Argument(
54     name='playlist', type='playlist', callback=current_playlist_callback,
55     help="""
56 :class:`hooke.playlist.Playlist` to act on.  Defaults to the current
57 playlist.
58 """.strip())
59
60 def playlist_name_callback(hooke, command, argument, value):
61         return hooke.playlists.free_name()
62
63 PlaylistNameArgument = Argument(
64     name='name', type='string', optional=True, callback=playlist_name_callback,
65     help="""
66 Name of the new playlist (defaults to an auto-generated name).
67 """.strip())
68
69 def all_drivers_callback(hooke, command, argument, value):
70     return hooke.drivers
71
72
73 # Define commands
74
75 class NextCommand (Command):
76     """Move playlist to the next curve.
77     """
78     def __init__(self):
79         super(NextCommand, self).__init__(
80             name='next curve',
81             arguments=[PlaylistArgument],
82             help=self.__doc__)
83
84     def _run(self, hooke, inqueue, outqueue, params):
85         params['playlist'].next()
86
87 class PreviousCommand (Command):
88     """Move playlist to the previous curve.
89     """
90     def __init__(self):
91         super(PreviousCommand, self).__init__(
92             name='previous curve',
93             arguments=[PlaylistArgument],
94             help=self.__doc__)
95
96     def _run(self, hooke, inqueue, outqueue, params):
97         params['playlist'].previous()
98
99 class JumpCommand (Command):
100     """Move playlist to a given curve.
101     """
102     def __init__(self):
103         super(JumpCommand, self).__init__(
104             name='jump to curve',
105             arguments=[
106                 PlaylistArgument,
107                 Argument(name='index', type='int', optional=False, help="""
108 Index of target curve.
109 """.strip()),
110                 ],
111             help=self.__doc__)
112
113     def _run(self, hooke, inqueue, outqueue, params):
114         params['playlist'].jump(params['index'])
115
116 class IndexCommand (Command):
117     """Print the index of the current curve.
118
119     The first curve has index 0.
120     """
121     def __init__(self):
122         super(IndexCommand, self).__init__(
123             name='curve index',
124             arguments=[
125                 PlaylistArgument,
126                 ],
127             help=self.__doc__)
128
129     def _run(self, hooke, inqueue, outqueue, params):
130         outqueue.put(params['playlist']._index)
131
132 class CurveListCommand (Command):
133     """Get the curves in a playlist.
134     """
135     def __init__(self):
136         super(CurveListCommand, self).__init__(
137             name='playlist curves',
138             arguments=[
139                 PlaylistArgument,
140                 ],
141             help=self.__doc__)
142
143     def _run(self, hooke, inqueue, outqueue, params):
144         outqueue.put([c for c in params['playlist']])
145
146 class SaveCommand (Command):
147     """Save a playlist.
148     """
149     def __init__(self):
150         super(SaveCommand, self).__init__(
151             name='save playlist',
152             arguments=[
153                 PlaylistArgument,
154                 Argument(name='output', type='file',
155                          help="""
156 File name for the output playlist.  Defaults to overwriting the input
157 playlist.
158 """.strip()),
159                 ],
160             help=self.__doc__)
161
162     def _run(self, hooke, inqueue, outqueue, params):
163         params['playlist'].save(params['output'])
164
165 class LoadCommand (Command):
166     """Load a playlist.
167     """
168     def __init__(self):
169         super(LoadCommand, self).__init__(
170             name='load playlist',
171             arguments=[
172                 Argument(name='input', type='file', optional=False,
173                          help="""
174 File name for the input playlist.
175 """.strip()),
176                 Argument(name='drivers', type='driver', optional=True,
177                          count=-1, callback=all_drivers_callback,
178                          help="""
179 Drivers for loading curves.
180 """.strip()),
181                 ],
182             help=self.__doc__)
183
184     def _run(self, hooke, inqueue, outqueue, params):
185         p = FilePlaylist(drivers=params['drivers'], path=params['input'])
186         p.load()
187         hooke.playlists.append(p)
188         outqueue.put(p)
189
190 class AddCommand (Command):
191     """Add a curve to a playlist.
192     """
193     def __init__(self):
194         super(AddCommand, self).__init__(
195             name='add curve to playlist',
196             arguments=[
197                 PlaylistArgument,
198                 Argument(name='input', type='file', optional=False,
199                          help="""
200 File name for the input :class:`hooke.curve.Curve`.
201 """.strip()),
202                 Argument(name='info', type='dict', optional=True,
203                          help="""
204 Additional information for the input :class:`hooke.curve.Curve`.
205 """.strip()),
206                 ],
207             help=self.__doc__)
208
209     def _run(self, hooke, inqueue, outqueue, params):
210         params['playlist'].append_curve_by_path(params['input'],
211                                                 params['info'])
212
213 class AddGlobCommand (Command):
214     """Add curves to a playlist with file globbing.
215
216     Adding lots of files one at a time can be tedious.  With this
217     command you can use globs (`data/curves/*.dat`) to add curves
218     for all matching files at once.
219     """
220     def __init__(self):
221         super(AddGlobCommand, self).__init__(
222             name='glob curves to playlist',
223             arguments=[
224                 PlaylistArgument,
225                 Argument(name='input', type='glob', optional=False,
226                          help="""
227 File name glob for the input :class:`hooke.curve.Curve`.
228 """.strip()),
229                 Argument(name='info', type='dict', optional=True,
230                          help="""
231 Additional information for the input :class:`hooke.curve.Curve`.
232 """.strip()),
233                 ],
234             help=self.__doc__)
235
236     def _run(self, hooke, inqueue, outqueue, params):
237         for path in sorted(glob.glob(params['input'])):
238             params['playlist'].append_curve_by_path(path, params['info'])
239
240 class RemoveCommand (Command):
241     """Remove a curve from a playlist.
242     """
243     def __init__(self):
244         super(RemoveCommand, self).__init__(
245             name='remove curve from playlist',
246             arguments=[
247                 PlaylistArgument,
248                 Argument(name='index', type='int', optional=False, help="""
249 Index of target curve.
250 """.strip()),
251                 ],
252             help=self.__doc__)
253
254     def _run(self, hooke, inqueue, outqueue, params):
255         params['playlist'].pop(params['index'])
256         params['playlist'].jump(params._index)
257
258 class FilterCommand (Command):
259     """Create a subset playlist via a selection function.
260
261     Removing lots of curves one at a time can be tedious.  With this
262     command you can use a function `filter` to select the curves you
263     wish to keep.
264     """
265     def __init__(self):
266         super(FilterCommand, self).__init__(
267             name='filter playlist',
268             arguments=[
269                 PlaylistArgument,
270                 PlaylistNameArgument,
271                 Argument(name='filter', type='function', optional=False,
272                          help="""
273 Function returning `True` for "good" curves.  `filter(curve) -> True/False`.
274 """.strip()),
275                 ],
276             help=self.__doc__)
277
278     def _run(self, hooke, inqueue, outqueue, params):
279         p = params['playlist'].filter(params['filter'])
280         hooke.playlists.add(p)
281         outqueue.put(p)
282
283 class NoteFilterCommand (FilterCommand):
284     """Create a subset playlist of curves with `.info['note'] != None`.
285     """
286     def __init__(self):
287         super(NoteFilterCommand, self).__init__()
288         self.name = 'note filter playlist'
289         self.arguments = [a for a in self.arguments if a.name != 'filter']
290
291     def _run(self, hooke, inqueue, outqueue, params):
292         params['filter'] = lambda curve : \
293             'note' in curve.info and curve.info['note'] != None
294         return super(NoteFilterCommand, self)._run(
295             hooke, inqueue, outqueue, params)